对象的属性类型
特性:描述属性的各种特性;特性是为了实现
JavaScript
引擎用的,因此在JavaScript
中不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对儿方括号中,例如[[Enumerable]]
ECMAScript
中有两种属性:数据属性和访问器属性
数据属性
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。
- [[Writable]]:表示能否修改属性的值。
- [[Value]]:包含这个属性的数据值。
访问器属性
- [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。
- [[Enumerable]]:表示能否通过 for-in 循环返回属性。
- [[Get]]:在读取属性时调用的函数。
- [[Set]]:在写入属性时调用的函数。
要修改属性默认的特性,必须使用ECMAScript 5
的 Object.defineProperty()
方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是: configurable、 enumerable、 writable 和 value。
var book = {
_year: 2004,//_year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。
edition: 1
};
Object.defineProperty(book, "year", {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year = 2005;//year为访问器属性
alert(book.edition); //2
原型对象
函数中的prototype属性
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype
属性,这个属性指向函数的原型对象。
原型对象中的constructor属性
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
创建了自定义的构造函数之后,其原型对象默认只会取得 constructor 属性;至于其他方法,则都是从 Object 继承而来的。
实例对象中的_proto_属性
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部
属性),指向构造函数的原型对象。 ECMA-262 第 5 版中管这个指针叫[[Prototype]]
。虽然在脚本中没有标准的方式访问[[Prototype]]
,但 Firefox、 Safari 和 Chrome 在每个对象上都支持一个属性
__proto__
;而在其他实现中,这个属性对脚本则是完全不可见的。
实例、构造函数、原型对象的关系
- 构造函数的
prototype
属性存储指向该构造函数的原型对象的指针; - 原型对象的
constructor
属性存储指向该构造函数的指针; - 该构造函数创建的实例对象的
__proto__
属性存储指向该构造函数的原型对象的指针; - 实例对象与构造函数不存在直接关系,只有间接关系;
function Person(){};
//重写Person构造函数的原型对象
Person.prototype={
name:"TEST",
age:21
}
此时Person构造函数的原型对象中的constructor存储的是指向Object构造函数的指针。why?
答:因为重写了一个Person构造函数的原型对象,相当于重新创建一个Object对象,该实例对象中没有constructor属性,但是该实例对象中存在__proto__
属性,该属性指向了Object构造函数的原型对象,该原型对象中存在constructor属性,该属性的值为指向Object构造函数的指针。所以新的Person构造函数原型对象在没有constructor属性的时候,获取了Object构造函数原型对象的constructor属性。