学习面向对象javascript(5)内置对象

学习面向对象javascript(五)内置对象

在javascript中,提供了一些内置对象。Object就是其中一个,他是所有javascript对象的父对象。另外还有其他的一些。
基本上,内置对象可以分成三组:

  • 数据包装对象:Object,Array,Function,Boolean,Number,String。
  • 公共对象:Math,Date,RegExp。
  • 错误对象:Error对象

Object

Object是所有javascript对象的父对象。创建一个空对象你可以使用大括号方式或者构造函数方式。下面的两种是等效的:

var o = {};
var o = new Object();
 


一个空对象并不是完全没有用的,他其实已经包含了一些方法和属性,比如:
o.constructor属性返回构造器函数
o.toString()方法返回一个字符串形式的对象的描述,当一个对象被用作string来使用的是,这个方法会被执行,比如alert的时候。
o.valueOf()方法返回一个对象的单值,通常是对象自己,比如:

o.valueOf() === o;  // true

Array

Array()是一个内置函数,我们可以用它来作为创建数组的构造器。下面两种是等效的:

var a = new Array();
var a = [];
 


当使用Array()创建数组时,我们可以传入参数作为数组的元素。

var a = new Array(1,2,3,'four');
a;  // [1, 2, 3, "four"]
 


特殊的是,当我们只传入一个数字的时候。构造器会把这个数字作为数组的长度来创建一个数组。

var a2 = new Array(5);
a2;  // [undefined, undefined, undefined, undefined, undefined]
 


下面我们可以比较一下数组和对象。

var a = [], o = {};
 


在数组中,有一个length属性,而对象没有;

a.length;  // 0
typeof o.length;  // "undefined"
 


我们可以向数组和对象中添加数字或者非数字属性。

a[0] = 1; 
o[0] = 1;
a.prop = 2; 
o.prop = 2;
 


但是数组中的length属性只会计算数字属性的长度。

a.length;  // 1
 


length这个属性我们是可以手动设置的。
如果我们设置一个比当前大的一个数字,那么数组会开辟一些空的元素来填充数组,值为undefined。

a.length = 5;
a;  // [1, undefined, undefined, undefined, undefined]
 


如果把length设为比当前小的数字,数组将会把多余的元素截断。

a.length = 2;
a;  // [1, undefined]

 

Array里面还包含了其他一些有用的方法,比如sort(), join(), slice()。
我们可以试一些方法。

var a = [3, 5, 1, 7, 'test'];
 


push()方法和pop()方法在对栈操作时比较有用。
push方法可以把一个元素加在数组的最后面,pop方法会删除最后一个元素。所以a.push('new')相当于a[a.length]='new',而a.pop()相当于a.length--。
push方法返回加入新元素以后的数组的长度,pop方法返回删除掉的元素。

a.push('new');  // 6
a;  // [3, 5, 1, 7, "test", "new"]
a.pop();  // "new"
a;  // [3, 5, 1, 7, "test"]
 


sort()方法可以对一个数组进行自然排序,并返回排序后的数组。

var b = a.sort();
b;  // [1, 3, 5, 7, "test"]
a;  // [1, 3, 5, 7, "test"]
 


可见,a,b指向了同一个数组。

join()返回一个用给定值把各个数组元素连接起来的字符串。

a.join(' : ');  // "1 : 3 : 5 : 7 : test"
 


slice()方法返回一个数组指定范围的一个拷贝数组,意思就是拷贝出数组的一个范围内元素,而不改变数组本身。

b = a.slice(1, 3);  // [3, 5]
b = a.slice(0, 1);  // [1]
b = a.slice(0, 2);  // [1, 3]
a;  // [1, 3, 5, 7, "test"]
 


splice()方法会修改原数组,它会删掉指定部分的元素,并可以用新的元素来填补这些空缺。前两个参数表示起始位置和终止位置,其他的参数表示用于填补的新元素。

b = a.splice(1, 2, 100, 101, 102);  // [3, 5]
a;  // [1, 100, 101, 102, 7, "test"]
 


也可以不加填补的新元素。

a.splice(1, 3);  // [100, 101, 102]
a;  // [1, 7, "test"]

 Function

另一种创建方法的方式是使用内置对象Function。但是这种方式不建议使用。
以下是几种创建方法的方式:

function sum(a, b) {return a + b;};
sum(1, 2);  // 3
var sum = function(a, b) {return a + b;};
sum(1, 2);  // 3
var sum = new Function('a', 'b', 'return a + b;');
sum(1, 2);  // 3
 


当使用Function()构造一个函数时,首先需要传入函数的参数,然后传入函数体的源代码。Javascript引擎会评估传入的源代码,并生成一个新的方法返回。所以,使用这种方式和使用eval()函数有着同样的缺点。
如何使用Function构造器来构造一个含有很多参数的方法时,可以将参数用逗号隔开,一次性传入。

var first = new Function('a, b, c, d', 'return arguments;');
first(1,2,3,4);  // [1, 2, 3, 4]
var second = new Function('a, b, c', 'd', 'return arguments;');
second(1,2,3,4);  // [1, 2, 3, 4]
var third = new Function('a', 'b', 'c', 'd', 'return arguments;');
third(1,2,3,4);  // [1, 2, 3, 4]
 


像其他对象一样,Function有constructor属性,他指向Function()构造函数。

function myfunc(a){
    return a;
}
myfunc.constructor;  // Function()

 

Function的length属性包含了函数接收的参数的个数。

function myfunc(a, b, c){
    return true;
}
myfunc.length;  // 3
 


另外,有一个属性叫做caller,该属性不是ECMA标准定义的,而是由具体的浏览器提供的。他返回函数的一个调用该函数的函数的引用。比如,有一个函数A被函数B调用,如果在函数A中有A.caller。那么它将返回函数B。

function A(){
    return A.caller;
}
function B(){
    return A();
}
B();  // B()
 


如果我们直接访问函数A,那么A.caller将返回null。

A();  // null
 


我们可以用toString函数来得到函数的源代码。

function myfunc(a, b, c) {return a + b + c;}
alert(myfunc.toString());

弹出

"function myfunc(a, b, c) {
      return a + b + c;
}"


但是如果你试图用这种方法来返回内置函数的源代码,那是不行的。

alert(eval.toString());
 

弹出
"function eval() {
      [native code]
}"
另外有两个有用的方法是call和apply。这两个方法允许对象借用其他对象的方法并执行他们。这样做可以使代码能够重用。

var some_obj = {
  name: 'Ninja',
  say: function(who){
    return 'Haya ' + who + ', I am a ' + this.name;
  }
}
 


我们可以使用this.name来访问它的私有属性name。

some_obj.say('Dude');  // "Haya Dude, I am a Ninja"
 


现在我们定义一个对象my_obj。

my_obj = {name: 'Scripting guru'};
 


这时我们可以用call方法在some_obj对象中来得到my_obj的name属性。

some_obj.say.call(my_obj, 'Dude');  // "Haya Dude, I am a Scripting guru"
 


其实在这里面,当say函数被执行的时候,this的引用已经从some_obj转移到my_obj上面了。所以这时候this.name其实得到的是my_obj的name属性。用这种方法,我们可以有效的把this引用转移到其他对象上。来得到其他对象的方法或属性。
如果方法有多个参数,可以在call后面加入更多的参数。

some_obj.someMethod.call(my_obj, 'a', 'b', 'c');
 


如果第一个参数传入null,那么this将会引用全局对象。浏览器中就是window。

window.name='window';
some_obj.say.call(null, 'Dude');  // "Haya Dude, I am a window"
 


apply方法的其实也是和call一样的,不同的是,使用apply方法,后面函数的参数要放在一个数组里。例如:

some_obj.someMethod.apply(my_obj, ['a', 'b', 'c']);
some_obj.someMethod.call(my_obj, 'a', 'b', 'c');
 


我们知道,函数中有个属性是arguments,它包含了所有传入的参数。arguments其实只是一个类似数组的一个对象,因为他可以像数组一样包含索引元素,有length属性,但是他并没有数组对象的sort,slice这些方法。不过它有一个callee属性。如果你定义一个函数并return arguments.callee,当执行这个函数的时候,将得到它自己的引用。

function f(){
    return arguments.callee;
}
f();  // f()
 


因此,我们可以用你们函数来重复调用他自己

(
  function(count){
    if (count < 5) {
      alert(count);
      arguments.callee(++count);
    }
  }
)(1)
 


这段代码将连续弹出1,2,3,4.

Boolean

对于Boolean,它只不过是对基础数据类型boolean的包装。
我们可以用new关键字来创建一个Boolean对象。

var b = new Boolean();
typeof b;  // "object"
typeof b.valueOf();  // "boolean"
b.valueOf();  // false
 


可见,用Boolean构造器创建的是一个对象。我们可以使用他的valueOf方法来返回它的boolean值。
总的来说,这样的做法我们用的并不多。有时我们可能会直接调用Boolean函数来转换一个非boolean的值。这相当于使用“!!value”。

Boolean("test");  // true
Boolean("");  // false
Boolean({});  // true
 


除了我们知道的空字符串,null,0,undefined,NaN,false这6个值,其他的值都会被转换成false。即使是空对象和false的Boolean对象,一切对象都会被转换为true。

var b1 = new Boolean(true);
b1.valueOf();  // true
var b2 = new Boolean(false);
b2.valueOf();  // false
Boolean(b1);  // true
Boolean(b2);  // true

 Number

我们通常会用到Number这个对象来转换一个值为数字或者创建一个对象。

var n = Number('12.12');
typeof n; // "number"
var n = new Number('12.12');
typeof n; // "object"
 


没有用new操作符转换出来的就是一个数字。
Number函数还包含了几个有用的常量属性。
返回javascript所能处理的最大数值:

Number.MAX_VALUE; // 1.7976931348623157e+308
 


返回javascript所能处理的最小数值:

Number.MIN_VALUE;  // 5e-324
 


返回正无穷

Number.POSITIVE_INFINITY;  // Infinity
 


返回负无穷

Number.NEGATIVE_INFINITY;  // -Infinity
 


返回NaN

Number.NaN;  // NaN
 


Number对象还提供了toFixed(), toPrecision(),toExponential()这3个方法。
toFixed()可以将一个数字四舍五入,保留指定的小数位数以后,以string返回。

Math.PI;  // 3.141592653589793
Math.PI.toFixed(2);  // "3.14"
 


toExponential()将会把一个数字以指数的形式,保留指定小数位数后返回string。

var n = new Number(56789);
n.toExponential(2);  // "5.68e+4"
 


toPrecision()可以指定有效数字位数,将数字以string返回。

var n = new Number(56789);
n.toPrecision(2);  // "5.7e+4"
n.toPrecision(5);  // "56789"
n.toPrecision(4);  // "5.679e+4"
var n = new Number(Math.PI);
n.toPrecision(4);  // "3.142"
 


另外,number的toString方法还可以传入进制参数。默认是十进制。

var n = new Number(255);
n.toString();  // "255"
n.toString(10);  // "255"
n.toString(16);  // "ff"
(3).toString(2);  // "11"
3.toString(10);  // "3"

 String

对于String这个内置对象,它同样包含了很多方法。其中值得注意的是slice方法和substring方法。他们都可以用来截取字符串中的一段字符。不同的是,当结束位置参数是-1的时候,他们的结果是不同的。

var s = "Couch potato";
s.substring(1,-1);  // "C"
s.slice(1,-1);  // "ouch potat"

 

substring(1,-1)相当于substring(1,0),slice(1,-1)相当于slice(1, s.length - 1)。
除了前面这些内置的数据包装对象外,还有Math,Date,RegExp对象,以及Error对象。