提醒一下
阅读本文,你需要了解JavaScript的原型链相关知识。
进入正题
先看这么一句代码:
obj.a = 'abc';
这段代码的意思是,给obj对象设置属性。就是修改obj对象的a属性或添加一个属性a。
尽管代码很简单,但是不一定能赋值成功。
下面我们完整的讲解下赋值的过程:
obj.a = 'abc';
- 如果obj对象中存在自有属性a,且a属性为普通数据访问属性,且a属性是可写的(即属性描述符writable为true)。那么这条赋值语句才会修改a的属性值。
请看例子:
var obj = {
a: 'aaa'
};
//将b属性定义为只读的
Object.defineProperty(obj, 'b', {
writable: false,
enumerable:true,
configurable:true,
value: 'bbb',
});
console.log(obj); //{ a: 'aaa', b: 'bbb' }
obj.a = 'abc';
obj.b = 'abc';
console.log(obj); //非严格模式下 { a: 'abc', b: 'bbb' }
上面的例子中,b为只读属性,因此赋值操作失败。
如果obj对象没有a属性,那么会在obj原型链上找。如果原型链上找不到a属性,a就会被直接添加到obj上。
-
如果obj对象没有a属性,那么会在obj原型链上找。如果原型链上找到了a属性。那么情况就有点复杂了。分为以下三种情况:
如果a为普通数据访问属性,并且是可写的(writable:true),那么就会直接在obj对象中添加一个名为a的属性。
如果a为普通数据访问属性,但是是只读的(writable:false),那么就无法在obj对象上添加新属性。严格模式下,会抛出一个错误。否则,赋值语句无效,被忽略。
如果a是一个
setter
,那就一定会调用这个setter。a不会被添加到obj对象中,也不会重新定义a这个setter
。
请看例子:
var pro = {}; Object.defineProperties(pro, { a: { value: '原型上的a', writable: true, configurable: true, enumerable: true }, b: { value: '原型上的b', writable: false, configurable: true, enumerable: true } }) var obj = Object.create(pro); console.log(obj.a, obj.b); //原型上的a 原型上的b obj.a = '新增属性a'; obj.b = '新增属性b'; console.log(obj.a, obj.b); //新增属性a 原型上的b console.log(obj.hasOwnProperty('a')); //true console.log(obj.hasOwnProperty('b')); // false
上面的例子中,结果可以发现,我们在obj上新增了属性a,但是没有新增属性b。因为原型对象中b的属性描述符writable:false。如果这个时候,你还想给obj对象添加属性b,那么请使用
Object.defineProperty
方法。
最后再来看个隐式赋值操作:
var pro = {
a:1,
}
var obj = Object.create(pro);
obj.a++;
console.log(obj.a); //2
console.log(obj.hasOwnProperty('a')); // true
上面这个例子中,一开始,obj对象自身是不包含a属性的。但是,经过一个++操作后,obj对象有了自有属性a。原因是:obj.a++ 操作相等于 obj.a = obj.a+1; 这里有个显示的赋值。