本篇开始看下js对象原型[[Prototype]]
。
js中的对象有一种特殊的内置属性 [[Prototype]]
,其实就是对于其他对象的引用。几乎所有的对象在创建时都 [[Prototype]]
属性都会被赋予一个非空的值。
1var obj = {
2 a: 2
3}
4console.log(obj.a); // 2
5var newObj = Object.create(obj);
6console.log(newObj.a); // 2
上例的newObj
对象的[[Prototype]]
属性指向obj
对象。
当试图引用对象的属性时会触发[[Get]]
操作,例如obj.a
和newObj.a
。对于默认的[[Get]]
操作来说,第一步是检查对象本身是否有这个属性,如果有的话就使用它。如果对象本身没有这个属性,就需要使用到对象的内置属性 [[Prototype]]
了,[[Get]]
操作会访问对象的[[Prototype]]
链,对于上例的newObj.a
操作而言就是会继续访问其原型链上层的obj
对象。
现在我们明白访问对象的属性时,会先查找对象本身,如本身没有对应属性时,会向该对象的原型链上层对象查找,找到则返回该属性的值,如始终没有找到,则返回undefined
。
那么这个始终没有找到的尽头在哪?就在Object.prototype
。它是js中所有对象的源头,Object.prototype
的再上一层也有,但是null
了。
不光访问对象的属性可能会查找其原型链,为对象属性设置值时同样也可能会查找该对象的原型链。
通常为对象属性设置值我们采用=
赋值操作符来进行,当为对象obj的foo属性设置值时:
1obj.foo = "bar";
obj.foo
总是会选择原型链中最底层的foo属性。obj.foo = "bar";
会按照不同情况来执行:(下面有对应代码示例) 1// 1.
2var parentObj = {foo: 10};
3var obj = Object.create(parentObj);
4obj.foo = 5;
5console.log(obj.foo); // 5
6
7// 2.
8var parentObj = {};
9Object.defineProperty(parentObj, "foo", {
10 value: 10,
11 writable: false
12});
13var obj = Object.create(parentObj);
14obj.foo = 5;
15console.log(obj.foo); // 10 无法修改已有属性或在obj对象上创建屏蔽属性 非严格模式时忽略obj.foo = 5;操作,严格模式时直接报错
16
17// 3.
18var parentObj = {
19 get foo(){
20 return this.res;
21 },
22 set foo(val){
23 this.res = val * 4;
24 }
25}
26parentObj.foo = 10;
27console.log(parentObj.foo); // 40
28
29var obj = Object.create(parentObj);
30obj.foo = 3;
31console.log(obj.foo); // 12 继续调用原型链上层对象上 setter,
32console.log(obj.hasOwnProperty("foo")); // false 并且foo还不会被添加到obj对象上
如果希望在第2和第3种情况也能屏蔽foo属性,就不能使用=
赋值操作符,而应使用Object.defineProperty()
来向obj对象添加foo。
1// 2.
2var parentObj = {};
3Object.defineProperty(parentObj, "foo", {
4 value: 10,
5 writable: false
6});
7var obj = Object.create(parentObj);
8Object.defineProperty(obj, "foo", {
9 value: 5,
10 writable: false
11})
12console.log(obj.foo); // 5 这回可以在obj对象创建屏蔽属性foo了,值也为最新值 5
13
14// 3.
15var parentObj = {
16 get foo(){
17 return this.res;
18 },
19 set foo(val){
20 this.res = val * 4;
21 }
22}
23parentObj.foo = 10;
24console.log(parentObj.foo); // 40
25
26var obj = Object.create(parentObj);
27Object.defineProperty(obj, "foo", {
28 value: 7
29})
30console.log(obj.foo); // 7
你看,所以如果确实想改,也是有办法的,用Object.defineProperty()
就行。
-------------------------------- 热门文章 --------------------------------
设计模式>>>