不通過對象的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中的屬性進行遞增。