由于继承关系,所有属性都有以下方法(熟记)。
Object 基本方法 | 说明 |
---|---|
constructor | 用于创建当前对象的函数。在前面的例子中,这个属性的值就是 Object() 函数。 |
hasOwnProperty(propertyName) | 用于判断当前对象实例(不是原型)上是否存在给定的属性。要检查的属性名必须是字符串(如 o.hasOwnProperty("name") ) 或符号。 |
isPrototypeOf(object) | 用于判断当前对象是否为另一个对象的原型。 |
propertyIsEnumerable(propertyName) | 用于判断给定的属性是否可以使用( for-in 语句枚举。与 hasOwnProperty() 一样,属性名必须是字符串。 |
toLocaleString() | 返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。 |
toString() | 返回对象的字符串表示。 |
valueOf() | 返回对象对应的字符串、数值或布尔值表示。通常与 toString() 的返回值相同。 |
返回对象的字符串显示。它返回的字符串比较灵活,可能具有一个具体的值,也可能是一个对象的类型标志。
function F(x, y) {
// 构造函数 this.x = x;
this.y = y;
}
var f = new F(1, 2); // 实例化对象
alert(F.toString()); // 返回函数源代码
// 返回字符串 "[object,object]"
alert(f.toString());
toString() 返回信息简单,可以自己重新该方法。
Object.prototype.toString = function () {
return;
this.constructor.toString();
};
调用 f.toString() ,则返回函数的源代码,而不是字符串 "[object,object]" 。当然,重写不会影响 JavaScript 内置对象的 toString() 返回值,因为它们是只读的。
但把数据转换成是字符串时。 JavaScript 一般会调用 toString() 方法来实现。由于不同类型的对象在调用该方法时,说转换的字符串都不同,而且都有规律,所以,在使用过程中常用它来检测对象的类型,弥补 typeof 运算符和 constructor 属性在检测对象数据类型不足。
除了 toString() 方法外, Object 还定义了 toLocalString() 方法,该方法能够返回对象的本地字符串表示。不过 Object 对象定义 toLocaleString ()方法的默认返回值和 toString() 方法返回值相同。
JavaScript 在部分子类型中重写了 toString () 和 toLocaleString ()方法。例如,在 Array 中重写 toString() , 让其返回数组值的字符串组合。在 Date 中重写 toString (),让其返回当前日期字符串表示;在 Number 中,返回数字的字符串表示;在 Date 中重写 toLocalString() 让其返回当地格式化后的日期字符串。
返回对象的值。 Object 对象默认 valueOf () 和 toString ()方法返回值相同,但是部分类型对象重写了 valueOf ()。
Date 对象的 valueOf ()方法返回值是当前日期对象的毫秒数
var o = new Date(); // 对象实例
alert(o.toString());
// Sun Mar 14 2021 00:21:32 GMT+0800
中国标准时间; // 返回当前时间的 UTC 字符串
// 1615652522501 ( 当前日期距 1970 年 1 月1 日的毫秒数 )
alert(o.valueOf());
// Sun Mar 14 2021 00:24:34 GMT+0800 ( 中国标准时间 )
alert(Object.prototype.valueOf.apply(o));
// Object 对象默认返回当前时间的 UTC 字符串
在自定义类型时,除了重写 toString() 方法之外,也建议重写 valueOf() 方法。这样当读取自定义的对象的值时,避免返回值总是 "[object,object]" 。
在特定的环境下数据进行转换时, valueOf ()方法 的优先级比 toString ()方法优先级要高。因此,如果一个对象的 valueOf() 和 toString() 方法返回值不同,而希望转换为字符串为 toString() 方法的返回值时,就必须调用对象的 toString() 方法。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.valueOf = function () {
return '(' + this.x + ',' + this.y + ')';
};
Point.prototype.toString = function () {
return;
('[object , Point]');
};
var p = new Point(26, 68); // 实例化对象
alert('typeOf p = ' + p); // typeOf p = (26,68)
alert('typeOf p =' + p.toString()); // typeOf p =[object , Point]
继承关系决定,对象属性分两种:私有属性和继承属性。
F.prototype.name = ' 继承属性 ';
function F() {
this.name = ' 私有属性 ';
}
var a = new F();
alert(a.name); // 私有属性
alert(delete a.name); // true
alert(a.name);
// 继承属性 a.name = " 新值 ";
alert(a.name); // 新值
alert(delete a.name); // true
alert(a.name); // 继承属性
凡是构造函数的原型属性 ( 原型对象包含的属性 ) ,都有继承性,使用 hasOwnProperty() 方法检测,都返回 false 。但是,对于原型对象本身来说,则这些又是远行对象的私有属性,所以返回值为 true 。
F.prototype.name = ' 继承属性 ';
function F() {
this.name = ' 私有属性 ';
}
var a = new F();
console.log(a.hasOwnProperty('name')); // true
console.log('' + a.name); // 私有属性
console.log('' + delete a.name); // true
console.log("" + a.hasOwnProperty("name")); / / false;
console.log('' + a.name); // 继承属性
a.name = ' 新值 ';
console.log('' + a.name); //新值;
console.log('' + a.hasOwnProperty('name')); // true
console.log('' + delete a.name); // true
console.log('' + a.hasOwnProperty('name')); // false;
console.log('' + a.name); // 继承属性
hasOwnProperty() 方法只能够检测指定对象中是否含有指定的名称属性,但无法检查对象原型链是否包含某属性。
function w(a, b) {
return console.log(a.hasOwnProperty(b) + '');
}
var o = {
// 对象直接量
ol: {
// 子对象直接量
om: {
// 孙子对象直接量 name: 1 // 孙子对象直接量属性
},
},
};
w(o, 'ol'); // true ,说明 ol 是 o 的私有属性
w(o, 'om'); // false, 说明 om 不是 o 的私有属性
w(o.ol, 'om'); // true , 说明 om 是 ol 的私有属性
w(o, 'name'); // false , 说明 name 不是 o 的私有属性
w(o.ol, 'name'); // false , 说明 name 不是 ol 的私有属性
w(o.ol.om, 'name'); // true ,说明 name 是 om 的私有属性
在大多数情况下, in 运算符是探测对象属性中属性是否存在的最佳途径。然而在某种情况下,可能希望仅当一个属性是否是自有属性时才检查其是否存在。 in 运算符会检查私有属性和原型属性,所以不得不选择 hasOwnProperty() 方法。
var person = {
'first-name': 'gan',
'last-name': 'JinShi',
sayName: function () {
console.log(this['first-name'] + this['last-name']);
},
};
console.log('first-name' in person); // true
console.log(person.hasOwnProperty('first-name')); // true
console.log('toString' in person); // true
console.log(person.hasOwnProperty('toString')); // false
在大多数下, in 运算符可以探测对象中是否存在最好的属性,然而在某些情况下,可能仅当作是自身属性时才检测是否存在。 in 运算符会检查私有属性和原型属性,所以不得不选择 hasOwnProperty() 方法。
在 JavaScript 中, Function 预定的 prototype 属性,该属性指向一个原型对象。当定义构造函数时,系统会自动创建一个对象,并传递给 prototype 属性,这个对象称为原型对象,以便让所有实例对象共享。
当定义一个构造函数时,系统会自动创建一个对象,并传递给 prototype 属性,这个对象被称为 原型对象。原型对象可以储存构造类型的原型属性,以便让所有实例共享。
var f = function () {}; // 定义函数
f.prototype = {
a: 1,
b: function () {
return 2;
},
};
alert(f.prototype.a); // 1
alert(f.prototype.b()); // 2
当使用 new 运输符调用函数时,就会创建一个实例对象,这个实例对象将继承构造函数的原型对象的所有属性。
var o = new f(); // 实例对象
alert(o.a); // 访问原型对象的属性
alert(o.b()); // 访问原型对象的属性
函数的原型对象可以是 Object.prototype 或 Function.prototype :
var f = function () {};
console.log(Object.prototype.isPrototypeOf(f)); // true
console.log(Function.prototype.isPrototypeOf(f)); // true
Object 和 Function 对象的原型对象比较特殊。
alert(Function.prototype.isPrototypeOf(Object)); // true
alert(Object.prototype.isPrototypeOf(Object)); // true
alert(Function.prototype.isPrototypeOf(Function)); // true
alert(Object.prototype.isPrototypeOf(Function)); // true
函数的原型对象可以是 Object.prototype, 或者是 Function.prototype 但是, Object.prototype 的原型对象只能是 Object.prototype, 而 Function.prototype 的原型对象可以是 Object.prototype, 也可以是 Function.prototype
alert(Object.prototype.isPrototypeOf(Object.prototype)); // false
alert(Object.prototype.isPrototypeOf(Function.prototype)); // true
alert(Function.prototype.isPrototypeOf(Function.prototype)); // false
alert(Function.prototype.isPrototypeOf(Object.prototype)); // false
上例,在书中显示结果正好与实测相反,不知原因。
在面对对象的编程中,类不能直接访问,必须实例化后才可以访问。大多数方法和属性与类的实例产生关系。但静态属性和方法与类自身直接联系,可以直接从类访问,也就是说静态成员是在类上操作,而不是在实例上操作。 JavaScript 核心对象中的 math 和 global 都是静态对象,不需要实例化,就可以直接访问。
类的静态成员(属性和方法)包括私有和公共两种类型,不管是公共还是私有,它在系统只有一个副本,也就是说,它们不会被分成多份传递给不同值,而是 通过函数指针进行引用 。
var F = (function () {
var _a = 1;
this.a = _a;
this.get1 = function () {
return _a;
};
return function () {
this.get2 = function () {
return _a;
};
this.set2 = function (x) {
_a = x;
};
};
})();
F.get3 = function () {
// 静态公共方法
return get1();
};
F.set3 = function (x) {
// 静态公共方法
set1(x);
};
F.a = a; //静态公共私有属性 a
与一般类的创建方法一样,这里的私有成员仍然被声明在构造器(即构造函数)内。并 借助 var 和 this 关键字来实现。但构造器却由原来的普通函数变成了内嵌函数,并且作为外层函数的返回值返回,形成闭包。
var F = (function () {
function set5(x) {
// 静态私有方法
_a = x;
}
function get5() {
// 静态私有方法
return _a;
}
})();
与其它方法相比,静态函数有一个优点,就是内存仅保留一份。
定义在构造器中的私有方法可以调用其中的静态私有方法,反之则不然。要判断一个私有方法是否应该被设置为静态方法,可以看它是否需要访问任何实例数据。如果不需要,那么就设置为静态方法,因为它只被创建一份。
定义类的静态公共方法和属性一般都在类的外面进行。这种静态的方法和属性一般可以直接访问,这实际上相当于把构造器作为命名空间使用。同时,由于它仍然属于构造器的一部分,所以这些静态方法和属性中可以访问闭包中的私有成员。
alert(F.get3()); // 1
alert(F.a); // 1
F.set3(2);
alert(F.get3()); // 2
位于外层函数声明之后的小括号很重要。它在代码带入之后就立即执行这个函数,而不是调用构造函数时。这个函数的返回值是另一个函数,它被赋值给 F 变量, F 因此就成为一个构造函数。在实例化 F 时,调用的就是这个内层函数。外层函数仅是用来创建一个可以储存静态私有成员的闭包。
F 的返回的内层函数,该值是一个构造函数,它无法访问外层的公共方法 get() 和 set() ,但是能够返回构造函数体内的公共方法 get2() 和 set2() 。
var a = new F(); // 实例化类 F
alert(a.get2()); // 1
a.set2(2);
alert(a.get2()); // 2