prototype
应该是Javascript里最核心的内容了。原型链继承的概念神马的估计都背熟了,但其实在应用中又该怎么玩呢?
原型链是什么
如果myObject
上不存在a
属性时,我们就将注意力转向对象的[[Prototype]]
链:
1 2 3 4 5 6
| var anotherObject = { a: 2 }; var myObject = Object.create( anotherObject ); myObject.a;
|
这个处理持续进行,直到找到名称匹配的属性,或者[[Prototype]]
链终结。如果在链条的末尾都没有找到匹配的属性,那么[[Get]]
操作的返回结果为undefined
。
原型链的屏蔽
而以下这个案例又说明了什么?
1 2 3 4 5 6 7 8 9 10 11 12
| var anotherObject = { a: 2 }; var myObject = Object.create( anotherObject ); myObject.a; anotherObject.a = 3; console.log(myObject.a); myObject.a = 4; console.log(anotherObject.a); anotherObject.a = 5; console.log(myObject.a);
|
[[Prototype]]
链怎么访问呢,现在浏览器提供了一个.__proto__
属性来查找原型链。可以这么实现:
1 2 3 4 5 6 7 8 9 10
| Object.defineProperty( Object.prototype, "__proto__", { get: function() { return Object.getPrototypeOf( this ); }, set: function(o) { Object.setPrototypeOf( this, o ); return o; } } );
|
其实,我们并不需要一堆new
和.prototype
就能很好的利用原型的特性来完成代码,直接使用对象的字面形式将拥有更简洁的语法和更好的可读性。
Object.create(..)
和替补
Object.create(..)
在ES5中被加入。你可能需要支持ES5之前的环境:
1 2 3 4 5 6 7
| if (!Object.create) { Object.create = function(o) { function F(){} F.prototype = o; return new F(); }; }
|
Object.create(..)
的这种用法是目前最常见的用法,因为他的这一部分是可以填补的。ES5标准的内建Object.create(..)
还提供了一个附加的功能,它是 不能 被ES5之前的版本填补的。如此,这个功能的使用远没有那么常见。为了完整性,让我么看看这个附加功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| var anotherObject = { a: 2 }; var myObject = Object.create( anotherObject, { b: { enumerable: false, writable: true, configurable: false, value: 3 }, c: { enumerable: true, writable: false, configurable: false, value: 4 } } ); myObject.hasOwnProperty( "a" ); myObject.hasOwnProperty( "b" ); myObject.hasOwnProperty( "c" ); myObject.a; myObject.b; myObject.c;
|
当然我们经常使用一些polyfill代码来实现并没有被广泛支持的新增功能,其中的可维护性和兼容性之间的取舍就看你自己啦。