ECMA-262第5版描述了对象属性的各种特征,对象的属性分为两种,数据属性和访问器属性(一个属性只能是数据属性或者访问器属性中的一种)。数据属性具有4个特性(描述符),即configurable, enumerable, writable, value,访问器属性具有4个属性,configurable, enumerable, getter, setter。当调用Object.defineProperty为对象属性设置描述符时,当设置了writable或者value之后,不能再对其设置getter或者setter属性,否则会报错:
var human={
name:"chengkang",
_wife:"pengke"
};
Object.defineProperty(human,"height",{writable:true,value:20,get:function(params) {
return 30;
}});
TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified
数据属性有4个特性,configurable, enumerable, writable, value.
如下:(注意使用Object.defineProperty来创建属性时,writable, enumerable, configurable若未指定则默认为false)
特性 | 数据类型 | 描述 | 默认值 |
---|---|---|---|
[[Value]] | 任何Javascript类型 | 包含这个属性的数据值。 | undefined |
[[Writable]] | Boolean | 如果该值为 false,则该属性的 [[Value]] 特性 不能被改变。 | true |
[[Enumerable]] | Boolean | 如果该值为 true,则该属性可以用 for…in 循环来枚举。 | true |
[[Configurable]] | Boolean | 如果该值为 false,则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。 | true |
var human={
name:"ck",
_wife:"pk"
};
human.name = "ck1n9";
Object.defineProperty(human,"height",{writable:true,value:20});
Object.defineProperty(human, "height", {
enumerable: true,
value: 20
});
//TypeError: can't redefine non-configurable property "height"
//可以想象,当第一次创建属性的时候指定了configurable为false的时候,想再设置其为ture就不可以了。
访问器属性会有一个或者两个访问器函数(get函数和set函数),明显,当只设置get函数时表示其只可读不可写,当只设置set函数时表示其只可写不可读。
特性 | 数据类型 | 描述 | 默认值 |
---|---|---|---|
[[Get]] | 函数对象或者 undefined | 该函数使用一个空的参数列表,能够在有权访问的情况下读取属性值。 | undefined |
[[Set]] | 函数对象或者 undefined | 该函数有一个参数,用来写入属性值。 | true |
[[Enumerable]] | Boolean | 如果该值为 true,则该属性可以用 for…in 循环来枚举。 | true |
[[Configurable]] | Boolean | 如果该值为 false,则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。 | true |
可以使用两种方法为对象添加getter:
a. 在对象初始化的时候为对象指定:
var human={
name:"ck",
_wife:"pk",
get myGirl() {
return this._wife;
}
};
console.log(human.myGirl);//pk
b. 调用Object.defineProperty来指定:
var human={
name:"ck",
_wife:"pk",
_age:20,
get myGirl() {
return this._wife;
}
};
Object.defineProperty(human,"age",{get:function() {
return this._age+1;
}});
console.log(human.age);//21
c.使用计算属性名:
var prop = "age";
var students = {
set currSt(name){
this.sts.push(name);
},
sts:[],
get [prop](){
if(prop == "age")
return 20;
else if(prop == "height")
return 180;
else
return undefined;
}
};
console.log(students[prop]);//20
当你需要访问返回动态计算值的属性,或者你可能需要反映内部变量的状态,而不需要使用显式方法调用。在JavaScript中,可以使用 getter 来实现,getter创建一个伪属性类型。
可以使用相同的方法来设置setter:
a. 初始化的时候指定:
var students = {
set currSt(name){
this.sts.push(name);
},
city:"chongq",
sts:[]
};
students.currSt = "ck";
students.currSt = "pk";
console.log(students.currSt);//由于currSt是伪属性,返回undefined
console.log(students.sts.join("--"));//ck--pk
b.调用Object.defineProperty:
Object.defineProperty(students,"home",{set:function(params) {
this.city = params;
}});
students.home = "anhui";
console.log(students.city);//anhui
c.使用计算属性名:
var expr = "foo";
var obj = {
baz: "bar",
set [expr](v) { this.baz = v; }
};
console.log(obj.baz); // "bar"
obj.foo = "baz"; // run the setter
console.log(obj.baz); // "baz"