1.什么是屏蔽属性
一条赋值语句引出的思考:
myObject.foo = "bar";
如果myObject 对象中包含名为foo 的普通数据访问属性,这条赋值语句只会修改已有的属
性值。
如果foo 不是直接存在于myObject 中,[[Prototype]] 链就会被遍历,类似[[Get]] 操作。
如果原型链上找不到foo,foo 就会被直接添加到myObject 上。
然而,如果foo 存在于原型链上层,赋值语句myObject.foo = "bar" 的行为就会有些不同
(而且可能很出人意料)。稍后我们会进行介绍。
如果属性名foo 既出现在myObject 中也出现在myObject 的[[Prototype]] 链上层, 那
么就会发生屏蔽。myObject 中包含的foo 属性会屏蔽原型链上层的所有foo 属性,因为
myObject.foo 总是会选择原型链中最底层的foo 属性。
2.屏蔽比我们想象中更加复杂
下面我们分析一下如果foo 不直接存在于myObject 中而是存在于原型链上层时myObject.foo = "bar" 会出现的三种情况。
- 如果在[[Prototype]] 链上层存在名为foo 的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在myObject 中添加一个名为foo 的新属性,它是屏蔽属性。
- 如果在[[Prototype]] 链上层存在foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在myObject 上创建屏蔽属性。如果运行在严格模式下,代码会抛出一个错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽。
- 如果在[[Prototype]] 链上层存在foo 并且它是一个setter(参见第3 章),那就一定会调用这个setter。foo 不会被添加到(或者说屏蔽于)myObject,也不会重新定义foo 这个setter。
3.你所不知道的屏蔽属性
大多数开发者都认为如果向[[Prototype]] 链上层已经存在的属性([[Put]])赋值,就一定会触发屏蔽,但是如你所见,三种情况中只有一种(第一种)是这样的。
如果你希望在第二种和第三种情况下也屏蔽foo,那就不能使用= 操作符来赋值,而是使用Object.defineProperty(..)(参见第3 章)来向myObject 添加foo。
4.JavaScript中的属性:定义和赋值的区别
1.赋值可能会调用原型上的setter(sub与sup里面有同名属性),定义会创建一个自身属性
2.原型链中的同名只读属性可能会阻止赋值操作(如上的非屏蔽操作),但不会阻止定义操作
3.赋值运算符不会改变原型链上的属性
4.只有通过定义操作,才能创建一个拥有指定特性的属性(Object.defineProperty的威力)
5.对象字面量中的属性是通过定义操作添加的
了解更详细的信息可以参考:http://www.cnblogs.com/ziyunf...