Javascript的原型、原型链与继承

JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。javascript

虽然这常常被看成是 JavaScript 的缺点被说起,其实基于原型的继承模型比传统的类继承还要强大。 实现传统的类继承模型是很简单,可是实现 JavaScript 中的原型继承则要困难的多。 (It is for example fairly trivial to build a classic model on top of it, while the other way around is a far more difficult task.)java

因为 JavaScript 是惟一一个被普遍使用的基于原型继承的语言,因此理解两种继承模式的差别是须要必定时间的。git

第一个不一样之处在于 JavaScript 使用原型链的继承方式。程序员

注意: 简单的使用 Bar.prototype = Foo.prototype 将会致使两个对象共享 相同的原型。 所以,改变任意一个对象的原型都会影响到另外一个对象的原型,在大多数状况下这不是但愿的结果。
function Foo() {     this.value = 42; } Foo.prototype = {     method: function() {} }; function Bar() {} // 设置Bar的prototype属性为Foo的实例对象 Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; // 修正Bar.prototype.constructor为Bar自己 Bar.prototype.constructor = Bar; var test = new Bar() // 建立Bar的一个新实例 // 原型链 test [Bar的实例]     Bar.prototype [Foo的实例]         { foo: 'Hello World' }         Foo.prototype             {method: ...};             Object.prototype                 {toString: ... /* etc. */};

上面的例子中,test 对象从 Bar.prototypeFoo.prototype 继承下来;所以, 它能访问 Foo 的原型方法 method。同时,它也可以访问那个定义在原型上的 Foo 实例属性 value。 须要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是 重复使用它原型上的那个实例;所以,全部的 Bar 实例都会共享相同value 属性。github

注意: 不要使用 Bar.prototype = Foo,由于这不会执行 Foo的原型,而是指向函数 Foo。 所以原型链将会回溯到 Function.prototype 而不是 Foo.prototype,所以 method 将不会在 Bar 的原型链上。

属性查找

当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。编程

到查找到达原型链的顶部 – 也就是 Object.prototype – 可是仍然没有找到指定的属性,就会返回 undefinedide

原型属性

当原型属性用来建立原型链时,能够把任何类型的值赋给它(prototype)。 然而将原子类型赋给 prototype 的操做将会被忽略。函数

function Foo() {} Foo.prototype = 1; // 无效

而将对象赋值给 prototype,正如上面的例子所示,将会动态的建立原型链。oop

性能

若是一个属性在原型链的上端,则对于查找时间将带来不利影响。特别的,试图获取一个不存在的属性将会遍历整个原型链。性能

而且,当使用 for in 循环遍历对象的属性时,原型链上的全部属性都将被访问。

扩展内置类型的原型

一个错误特性被常常使用,那就是扩展 Object.prototype 或者其余内置类型的原型对象。

这种技术被称之为 monkey patching 而且会破坏封装。虽然它被普遍的应用到一些 JavaScript 类库中好比 Prototype, 可是我仍然不认为为内置类型添加一些非标准的函数是个好主意。

扩展内置类型的惟一理由是为了和新的 JavaScript 保持一致,好比 Array.forEach

译者注这是编程领域经常使用的一种方式,称之为 Backport,也就是将新的补丁添加到老版本中。

总结

在写复杂的 JavaScript 应用以前,充分理解原型链继承的工做方式是每一个 JavaScript 程序员必修的功课。 要提防原型链过长带来的性能问题,并知道如何经过缩短原型链来提升性能。 更进一步,绝对不要扩展内置类型的原型,除非是为了和新的 JavaScript 引擎兼容。

相关文章
相关标签/搜索