javascript原型和原型鏈詳解
JavaScript不包含傳統的類繼承模型,而是使用prototypal原型模型。
雖然這經常被當作是 JavaScript 的缺點被提及,其實基於原型的繼承模型比傳統的類繼承還要強大。實現傳統的類繼承模型是很簡單,但是實現 JavaScript 中的原型繼承則要困難的多。
由於 JavaScript 是唯一一個被廣泛使用的基於原型繼承的語言,所以理解兩種繼承模式的差異是需要一定時間的,今天我們就來了解一下原型和原型鏈。
剛學習JavaScript的時候,一般都是用如下方式來寫程式碼:
[JavaScript] 純文字檢視 複製程式碼var decimalDigits = 2, tax = 5; function add(x, y) { return x + y; } function subtract(x, y) { return x - y; } //alert(add(1, 3));
通過執行各個function來得到結果,學習了原型之後,我們可以使用如下方式來美化一下程式碼。
原型使用方式一:
在使用原型之前,我們需要先將程式碼做一下小修改:
[JavaScript] 純文字檢視 複製程式碼var Calculator = function (decimalDigits, tax) { this.decimalDigits = decimalDigits; this.tax = tax; };
然後,通過給Calculator物件的prototype屬性賦值物件字面量來設定Calculator物件的原型。
[JavaScript] 純文字檢視 複製程式碼Calculator.prototype = { add: function (x, y) { return x + y; }, subtract: function (x, y) { return x - y; } }; //alert((new Calculator()).add(1, 3));
這樣,我們就可以new Calculator物件以後,就可以呼叫add方法來計算結果了。
原型使用方式二:
第二種方式是,在賦值原型prototype的時候使用function立即執行的表示式來賦值,即如下格式:
[JavaScript] 純文字檢視 複製程式碼Calculator.prototype = function () { } ();
它的好處在前面的帖子裡已經知道了,就是可以封裝私有的function,通過return的形式暴露出簡單的使用名稱,以達到public/private的效果,修改後的程式碼如下:
[JavaScript] 純文字檢視 複製程式碼Calculator.prototype = function () { add = function (x, y) { return x + y; }, subtract = function (x, y) { return x - y; } return { add: add, subtract: subtract } } (); //alert((new Calculator()).add(11, 3));
同樣的方式,我們可以new Calculator物件以後呼叫add方法來計算結果了。
分步宣告:
上述使用原型的時候,有一個限制就是一次性設定了原型物件,我們再來說一下如何分來設定原型的每個屬性吧。
[JavaScript] 純文字檢視 複製程式碼var BaseCalculator = function () { //為每個例項都宣告一個小數位數 this.decimalDigits = 2; }; //使用原型給BaseCalculator擴充套件2個物件方法 BaseCalculator.prototype.add = function (x, y) { return x + y; }; BaseCalculator.prototype.subtract = function (x, y) { return x - y; };
首先,宣告瞭一個BaseCalculator物件,建構函式裡會初始化一個小數位數的屬性decimalDigits,然後通過原型屬性設定2個function,分別是add(x,y)和subtract(x,y),當然你也可以使用前面提到的2種方式的任何一種,我們的主要目的是看如何將BaseCalculator物件設定到真正的Calculator的原型上。
[JavaScript] 純文字檢視 複製程式碼var BaseCalculator = function() { this.decimalDigits = 2; }; BaseCalculator.prototype = { add: function(x, y) { return x + y; }, subtract: function(x, y) { return x - y; } };
建立完上述程式碼以後,我們來開始:
[JavaScript] 純文字檢視 複製程式碼var Calculator = function () { //為每個例項都宣告一個稅收數字 this.tax = 5; }; Calculator.prototype = new BaseCalculator();
我們可以看到Calculator的原型是指向到BaseCalculator的一個例項上,目的是讓Calculator整合它的add(x,y)和subtract(x,y)這2個function,還有一點要說的是,由於它的原型是BaseCalculator的一個例項,所以不管你建立多少個Calculator物件例項,他們的原型指向的都是同一個例項。
[JavaScript] 純文字檢視 複製程式碼var calc = new Calculator(); alert(calc.add(1, 1)); //BaseCalculator 裡宣告的decimalDigits屬性,在 Calculator裡是可以訪問到的 alert(calc.decimalDigits);
上面的程式碼,執行以後,我們可以看到因為Calculator的原型是指向BaseCalculator的例項上的,所以可以訪問他的decimalDigits屬性值,那如果我不想讓Calculator訪問BaseCalculator的建構函式裡宣告的屬性值,那怎麼辦呢?這麼辦:
[JavaScript] 純文字檢視 複製程式碼var Calculator = function () { this.tax= 5; }; Calculator.prototype = BaseCalculator.prototype;
通過將BaseCalculator的原型賦給Calculator的原型,這樣你在Calculator的例項上就訪問不到那個decimalDigits值了,如果你訪問如下程式碼,那將會提升出錯。
[JavaScript] 純文字檢視 複製程式碼var calc = new Calculator(); alert(calc.add(1, 1)); alert(calc.decimalDigits);
重寫原型:
在使用第三方JS類庫的時候,往往有時候他們定義的原型方法是不能滿足我們的需要,但是又離不開這個類庫,所以這時候我們就需要重寫他們的原型中的一個或者多個屬性或function,我們可以通過繼續宣告的同樣的add程式碼的形式來達到覆蓋重寫前面的add功能,程式碼如下:
[JavaScript] 純文字檢視 複製程式碼//覆蓋前面Calculator的add() function Calculator.prototype.add = function (x, y) { return x + y + this.tax; }; var calc = new Calculator(); alert(calc.add(1, 1));
這樣,我們計算得出的結果就比原來多出了一個tax的值,但是有一點需要注意:那就是重寫的程式碼需要放在最後,這樣才能覆蓋前面的程式碼。
原型鏈:
在將原型鏈之前,我們先上一段程式碼:
[JavaScript] 純文字檢視 複製程式碼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.prototype 和 Foo.prototype 繼承下來;因此,它能訪問 Foo 的原型方法 method。同時,它也能夠訪問那個定義在原型上的 Foo 例項屬性 value。需要注意的是 new Bar() 不會創造出一個新的 Foo 例項,而是重複使用它原型上的那個例項;因此,所有的 Bar 例項都會共享相同的 value 屬性。
相關文章
- JavaScript學習總結(五)原型和原型鏈詳解JavaScript原型
- 再解 JavaScript 原型與原型鏈JavaScript原型
- ? 圖解原型和原型鏈圖解原型
- 圖解原型和原型鏈圖解原型
- 如何理解JavaScript的原型和原型鏈?JavaScript原型
- 徹底搞懂JavaScript原型和原型鏈JavaScript原型
- JavaScript 原型及原型鏈JavaScript原型
- JavaScript原型與原型鏈JavaScript原型
- JavaScript 原型 與 原型鏈JavaScript原型
- javascript——原型與原型鏈JavaScript原型
- 詳解JavaScript原型JavaScript原型
- JavaScript原型詳解JavaScript原型
- 前端開發:JS中原型和原型鏈的詳解前端JS原型
- js 原型鏈詳解JS原型
- javascript之原型與原型鏈JavaScript原型
- JavaScript中原型與原型鏈JavaScript原型
- JavaScript原型與原型鏈分析JavaScript原型
- 原型和原型鏈原型
- JavaScript從原型到原型鏈,細緻講解JavaScript原型
- JavaScript中的原型、原型鏈、原型模式JavaScript原型模式
- JavaScript 原型鏈JavaScript原型
- JavaScript原型鏈JavaScript原型
- JS原型鏈、prototype、__proto__、原型鏈繼承詳解JS原型繼承
- 7. JavaScript 原型與原型鏈JavaScript原型
- JavaScript系列之原型與原型鏈JavaScript原型
- 淺談JavaScript原型及原型鏈JavaScript原型
- JS原型和原型鏈JS原型
- 原型和原型鏈梳理原型
- 理解原型和原型鏈原型
- js原型鏈汙染詳解JS原型
- 徹底搞清楚 JavaScript 的原型和原型鏈JavaScript原型
- 原型和原型鏈 prototype和proto的區別詳情原型
- JavaScript之原型深入詳解JavaScript原型
- 深入JavaScript系列(六):原型與原型鏈JavaScript原型
- JavaScript深入之從原型到原型鏈JavaScript原型
- JavaScript 深入之從原型到原型鏈JavaScript原型
- 原型&原型鏈深度解讀原型
- JavaScript之原型鏈JavaScript原型