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 引擎兼容。

相關文章
相關標籤/搜索