JavaScript原型遞增陷阱

不通過對象的constructor.prototype對原型中的屬性進行遞增時候會觸發原型遞增陷阱。

 

本文通過一個Popup彈出框來解釋陷阱的出現情況,並說明如何找到陷阱和解決問題。並且本文假設你至少簡單瞭解JavaScript中的原型。

 

目錄:

 

記錄alert次數的彈出框

單實例調用

代碼解釋

彈出內容

添加一個實例

代碼解釋

彈出內容

debug

拆分bug

跳過陷阱

小結

相關閱讀:JavaScript-構造函數

 

記錄alert次數的彈出框

單實例調用

var Popup=function(){

}

Popup.prototype.alert=function(message){

    this.iMessageCount++;

    alert(message+'~alert過'+this.iMessageCount+'次');    

}

Popup.prototype.iMessageCount=0;

var oNimo=new Popup();

oNimo.alert('你好我是nimo!');//  alert 過1次

oNimo.alert('Nice to meet you,I am Nimo!');//  alert 過2次

代碼解釋

創建構造函數Popup

給Popup添加alert方法。彈出內容是消息加彈出次數,每次彈出遞增iMessageCount屬性。

添加公用屬性iMessageCount用於記錄彈出次數。

創建oNimo實例,並用oNimo彈出2次內容。

彈出內容

你好我是nimo!~alert過1次

Nice to meet you,I am Nimo!~alert過2次

目前看似一切正常,彈出內容和預計結果相同

 

添加一個實例

在上面的代碼底部添加如下代碼

 

var oDemo=new Popup();

oDemo.alert('我是demo!'); //alert過1次  

代碼解釋

創建oDemo實例,並用oDemo彈出2次內容。

彈出內容

我是demo!~alert過1次

oDemo的彈出結果應該是alert過3次,結果卻是alert過1次

 

debug

遇到bug先將相關對象輸出檢查

 

console.log(oNimo);//Popup {iMessageCount: 2, alert: function, iMessageCount: 0}

console.log(oDemo);//Popup {iMessageCount: 1, alert: function, iMessageCount: 0}

打印結果後發現原型中iMessageCount屬性並沒有遞增,依然是0。而oNimo和oDemo自身屬性中卻存儲著iMessageCount屬性,分別是2和1。說明this.iMessageCount++;遞增的是對象自身屬性並不是原型屬性。

 

拆分bug

既然問題出在this.iMessageCount++;那麼就對這行代碼進行詳細分析。

 

以下三行代碼實際相等

 

this.iMessageCount++

this.iMessageCount=this.iMessageCount+1

this.iMessageCount=this.constructor.prototype.iMessageCount+1

解釋

 

遞增操作

iMessageCount屬性等於iMessageCount屬性+1

因為一開始對象自身並沒有iMessageCount屬性而原型中有,所有結果是將原型屬性中的iMessageCount屬性+1並賦值給對象自身屬性中的iMessageCount屬性。

知識點:對象訪問一個屬性會首先查找自身屬性如果找不到自身屬性就查找對象的constructor中的prototype中的屬性(對象構造函數的原型中的屬性)。

 

跳過陷阱

如需對原型中的屬性進行遞增操作請直接對對象的constructor中的protorype中的屬性進行遞增。

 

修復後的代碼:

 

關鍵代碼: this.constructor.prototype.iMessageCount++;

 

完整代碼:

 

var Popup=function(){

}

Popup.prototype.alert=function(message){

    this.constructor.prototype.iMessageCount++;

    alert(message+'~alert過'+this.iMessageCount+'次');    

}

Popup.prototype.iMessageCount=0;

var oNimo=new Popup();

oNimo.alert('你好我是nimo!');//  alert 過1次

oNimo.alert('Nice to meet you,I am Nimo!');//  alert 過2次

 

var oDemo=new Popup();

oDemo.alert('我是demo!'); //alert過3次

小結

不通過對象的constructor.prototype對原型中的屬性進行遞增時候會觸發原型遞增陷阱。

如需對原型中的屬性進行遞增操作請直接對對象的constructor中的protorype中的屬性進行遞增。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *