在看《你不知道的JavaScript》上卷的<属性设置和屏蔽>时有点疑惑,查阅别人的日志解惑了许多,便记录下来。
遇到这个过程时:

1
myObject.foo = "bar"

分3种情况
1 如果 myOject 对象包含名为 foo 的普通数据访问属性时,这条语句只会修改已有的属性值。
2 如果 myOject 对象不包含名为 foo,[[Prototype]]链就会被遍历,类似[[Get]]操作。如果原型链上找不到 foo,foo 就会被直接添加到 myObject 上。
3 如果 foo 存在于原型链上层,那么有以下3种情况。
a.如果在[[Prototype]]链上层存在名为 foo 的普通数据访问属性并且没有被标记为只读,那就会直接在 myObject 中添加一个名为 foo 的新属性,它是屏蔽属性。

1
2
3
4
5
6
7
8
var anotherObject = { foo : "ban"};
anotherObject;// { foo : "ban"}
var myObject = Object.create(anotherObject);//myObject 的原型链指向了 anotherObject 了。
myOject;//{}
myObject.foo;//"ban" //此时,foo 属性是在原型链上层。
myObject.foo = "bar";
myOject;//{ foo : "bar"}
myObject.foo;//"bar";//此时,新的 foo 属性是在 myObject 上,原型链上层的 foo 属性被屏蔽了。

b.如果在[[Prototype]]链上层存在 foo,但是它被标记为只读,那么无法修改已有属性或者在 myObject 上创建屏蔽属性。如果允许在严格模式下,代码会抛出一个错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽。

1
2
3
4
5
6
7
8
9
10
var anotherObject = {};
Object.defineProperty(anotherObject,"foo",{
value:"ban",
writable:false
});
var myObject = Object.create(anotherObject);
myObject.foo="bar";
myObject;//{}
myObject.foo;//"ban"
//此时,myObject 原型链上层的 foo 属性没有被屏蔽。

c.如果在[[Prototype]]链上层存在 foo 并且它是一个 setter,那就一定会调用这个 setter。foo 不会被添加到 myObject,也不会重新定义 foo 这个 setter。

1
2
3
4
5
6
7
8
9
10
11
12
13
var anotherObject = {
get a() {
return this._a;
},

set a(val) {
this._a = val;
}
};
var myObject = Object.create(anotherObject);
obj.a = 2;
obj;//{_a: 2}
anotherObject.a;//undefined