代码改变世界

JavaScript原型递增陷阱

2013-12-04 08:52  nimojs  阅读(989)  评论(8编辑  收藏  举报

不通过对象的constructor.prototype对原型中的属性进行递增时候会触发原型递增陷阱。

本文通过一个Popup弹出框来解释陷阱的出现情况,并说明如何找到陷阱和解决问题。并且本文假设你至少简单了解JavaScript中的原型。

目录:

  1. 记录alert次数的弹出框
    1. 单实例调用
      1. 代码解释
      2. 弹出内容
    2. 添加一个实例
      1. 代码解释
      2. 弹出内容
    3. debug
      1. 拆分bug
    4. 跳过陷阱
  2. 小结

相关阅读: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次

代码解释

  1. 创建构造函数Popup
  2. 给Popup添加alert方法。弹出内容是消息加弹出次数,每次弹出递增iMessageCount属性。
  3. 添加公用属性iMessageCount用于记录弹出次数。
  4. 创建oNimo实例,并用oNimo弹出2次内容。

弹出内容

  1. 你好我是nimo!~alert过1次
  2. Nice to meet you,I am Nimo!~alert过2次

目前看似一切正常,弹出内容和预计结果相同

添加一个实例

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

var oDemo=new Popup();
oDemo.alert('我是demo!'); //alert过1次  

代码解释

  1. 创建oDemo实例,并用oDemo弹出2次内容。

弹出内容

  1. 我是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++;那么就对这行代码进行详细分析。

以下三行代码实际相等

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

解释

  1. 递增操作
  2. iMessageCount属性等于iMessageCount属性+1
  3. 因为一开始对象自身并没有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次

小结

  1. 不通过对象的constructor.prototype对原型中的属性进行递增时候会触发原型递增陷阱。
  2. 如需对原型中的属性进行递增操作请直接对对象的constructor中的protorype中的属性进行递增

原文地址:JavaScript原型递增陷阱 转载请注明出处