在阅读本文之前,请先查看继承与原型链一文以了解关于 JavaScript 继承和构造器原型的知识。
在 JavaScript 中一直在使用继承机制,但是本页面使用了一些 ECMAScript 5 中引入的方法。请查看这些方法的不同之处,并考虑它们是否可以效仿。
例子
B
继承于 A
:
function A(a){ this.varA = a; } A.prototype = { varA : null, doSomething : function(){ // ... } } function B(a, b){ A.call(this, a); this.varB = b; } B.prototype = Object.create(A.prototype, { varB : { value: null, enumerable: true, configurable: true, writable: true }, doSomething : { value: function(){ // override A.prototype.doSomething.apply(this, arguments); // call super // ... }, enumerable: true, configurable: true, writable: true } }); var b = new B(); b.doSomething();
最重要的两个地方是:
- 类型定义在了
prototype 属性中
- 使用了
Object.create() 来实现继承
原型
和 Object.getPrototypeOf
对于那些从 Java 或 C++ 转来的程序员来说,JavaScript 肯定会让他们感到困惑,因为 JavaScript 是动态的,完全运行时的,而且它竟然没有类,只有实例(对象)。有些人嘴里的“类”也仅仅是一个用来模拟类的函数对象。
你可能已经注意到了,在上例中,函数 A 有一个特殊的属性 prototype。这个属性主要是和 new 运算符一起工作的。当使用new运算符生成对象实例的时候,实例会有一个称之为 [[Prototype]]的内部属性,指向了构造函数的 prototype 属性指向的那个对象。比如,当你执行 var a1 = new A() 的时候,JavaScript 引擎内部会执行类似 a1.[[Prototype]] = A.prototype 这样的操作(在创建了a1指向的那个对象之后,但在运行A()之前)。
当你访问一个对象的属性时,JavaScript 会首先看这个属性是否存在于该对象自身上,如果没有,就会到它的内部属性 [[Prototype]] 指向的那个对象的身上找。这也就实现了,构造函数的 prototype 属性指向的那个对象上的所有属性被该构造函数的所有实例所共享,如果你改变了 prototype 属性指向的那个对象身上的某个属性的值,则所有的实例都会受到影响。
比如,基于上的那个例子,如果你执行了
var a1 = new A(); var a2 = new A();
那么 a1.doSomething
实际上访问的就是 Object.getPrototypeOf(a1).doSomething
,也就是你一开始定义的 A.prototype.doSomething
。更清楚点,也就是:
Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething
原型链的遍历是递归进行的,也就是说,查找过程是这样的:a1.doSomething
,Object.getPrototypeOf(a1).doSomething
,Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething
等等,一直到找到那个属性,或者到达原型链顶层(Object.getPrototypeOf
方法返回 null 的时候)。
所以,当你在执行:
var o = new Foo();
的时候,JavaScript 实际上给你做了类似这样的操作:
var o = new Object(); o.[[Prototype]] = Foo.prototype; o.Foo();
这时,如果你访问:
o.someProp;
它会首先查看 o 对象本身是否有属性
someProp。
如果没有,则检查 Object.getPrototypeOf(o).someProp
是否存在,如果仍不存在,就继续检查Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp,
依次类推。