给一个对象设置属性,这是对象的知识点,但是由于涉及到了原型链,就放在原型里了。
getter和setter都是隐藏函数,getter会在获取属性值时调用,setter会在设置属性值时调用。
当你给一个属性定义getter、setter或者两者都有,那这个属性就被定义为"访问描述符"。
对于访问描述符,JavaScript会忽略它们的value和writable特性,只关心set和get(还有configurable、enumerable)特性。
var obj = {
//给a定义一个getter
get a() {
return 1;
}
}
Object.defineProperty(obj,"b",{
//给b定义一个getter
get: function() {
return this.a*2;
},
enumerable: true
});
obj.a; //1
obj.b; //2
上面两种方式都会在对象中创建一个不包含值得属性,对这个属性的访问会自动调用一个隐藏函数,它的返回值会被当做属性访问的返回值:
var obj= {
//给a定义一个getter
get a() {
return 1;
}
};
obj.a = 2;
obj.a; //1
只定义了a的getter,赋值是没有意义的。所以getter和setter应当一起出现:
var obj = {
//给a定义一个getter
get a() {
return this._a;
},
//给a定义一个setter
set a(val) {
this._a = val*2;
}
};
obj.a = 1;
obj.a; //2
obj.a = 1;
1、如果obj中已经有了a属性(若原型链上层也有a属性,就会发生屏蔽),该语句会修改已有的属性值(总会选择原型链最底层的a属性)。
其实赋值会触发一个[[Put]]方法,对obj中已经有了a属性,它大概会检查下面这些内容:
1、属性是否是访问描述符?如果是并且存在setter就调用setter。
2、属性的数据描述符中writable是否是false?如果是,在非严格模式下静默失败,在严格模式下TypeError异常。
3、如果都不是,将该值设置为属性的值。
2、如果obj中没有a属性,就会遍历原型链。如果原型链上也没有找到a属性,a就被添加到obj上。
3、如果obj中没有a属性,原型链上层有a属性,那么有三种情况:
var anotherObj = {a:1};
var obj = Object.create(anotherObj);
obj.a = 2;
obj; //{a: 2}
var anotherObj = {};
Object.defineProperty(anotherObj,"a",{
value: 1,
writable: false
});
var obj = Object.create(anotherObj);
obj.a = 2; //该语句是没有效果的
obj; //{}
obj.a; //1
但是,也可以屏蔽a属性:
var anotherObj = {};
Object.defineProperty(anotherObj,"a",{
value: 1,
writable: false
});
var obj = Object.create(anotherObj);
Object.defineProperty(obj,"a",{
value: 2
});
obj; //{a: 2}
屏蔽a属性,不能使用=操作符来赋值,而是通过Object.defineProperty()向obj添加a属性。
var anotherObj = {
get a() {
return this._a;
},
set a(val) {
this._a = val;
}
};
var obj = Object.create(anotherObj)
obj.a = 2;
obj; //{_a: 2}
同上,也可以通过Object.defineProperty()来屏蔽a属性:
var anotherObj = {
get a() {
return this._a;
},
set a(val) {
this._a = val;
}
};
var obj = Object.create(anotherObj);
Object.defineProperty(obj,"a",{
value: 2
});
obj; //{a: 2}
注意:有时候会产生隐式屏蔽:
var anotherObj = {a: 2};
var obj = Object.create(anotherObj);
anotherObj.a; //2
obj.a; //2
anotherObj.hasOwnProperty("a"); //true
obj.hasOwnProperty("a"); //false
obj.a++;
anotherObj.a; //2
obj.a; //3
obj.hasOwnProperty("a"); //true
修改委托属性时要小心,如果想要anotherObj.a的值增加,唯一的办法就是anotherObj.a++。