BeWithYou

胡搞的技术博客

  1. 首页
  2. web前端/Javascript
  3. 记录Cocos2d-js中关于原型的一个坑

记录Cocos2d-js中关于原型的一个坑


记录Cocos2d-js中关于原型的一个坑

       其实不是Cocos框架的坑,还是自己对于这块理解不够深入。昨天刚写了一篇日志,讲Javascript中的面向对象相关实现的,今天就踩了坑。
       故事是这样的。假如我们像下面这样声明一个类。

var MessageListModel = cc.Class.extend({
    _className:"MesageListModel",
    messageList:[],
    messageNum:0,
    ctor:function(){
        //this._super();
    },
    addMessage:function(arr){
        var that = this;
        arr.forEach(function(e){
            that.messageList.push(e);
        });
    },
    setNum:function(num){
        this.messageNum=num;
    }
});

       看上去没问题吧,因为messageList初始化为[]了,所以把新消息直接push进去即可。因为需要翻页加载,所以我们增加一个接口用于人工设定消息数量setNum()

       但是实际情况却不是如此,我们会发现,每次new出来一个新的MessageListModel对象之后,它的messageList属性居然不是空的!!而是上次用过的对象残留下来的数组。即使将老的对象强行delete()掉也不行。

       问题出在哪里了呢,想想看框架也不应该那么智能,强行为我留着上次用过的那个数组,那段内存。既然不是框架的问题,那很大概率就是类的实现上出了差错。

       上篇文章提到过,如果一个对象自己对于原型中已有的变量,又做了定义,那么则会暂时覆盖原型中的值。只要把这个变量再delete()掉,就会让原型的字段重新暴露出来。我们再回到Cocos2d-js关于extend方法实现的那段代码上来,在为声明的对象设置属性的时候是这样的:

if (releaseMode && isFunc && override && hasSuperCall) {
    desc.value = ClassManager.compileSuper(prop[name], name, classId);
    Object.defineProperty(prototype, name, desc);
} else if (isFunc && override && hasSuperCall) {
    desc.value = (function (name, fn) {
            return function () {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-Class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);
            this._super = tmp;

            return ret;
            };
            })(name, prop[name]);
    Object.defineProperty(prototype, name, desc);
} else if (isFunc) {
    desc.value = prop[name];
    Object.defineProperty(prototype, name, desc);
} else {
    prototype[name] = prop[name];
}

       框架是将出现在extend参数里那个json对象里的每个属性,都设置到新的类的原型里,比如例子中的messageList变量,也会算在原型中。所以,如果我们不在ctor或者读取这个变量之前对其重新定义,而是直接push的话,使用的是原型中的messageList!

       所以解决这个问题,只需要在ctor中对变量重新初始化。或者干脆一点,不要在外面定义这些变量了!

var MessageListModel = cc.Class.extend({
    _className:"MesageListModel",
    ctor:function(){
        //this._super();
        this.messageList = [];
        this.messageNum = 0;
    },
    addMessage:function(arr){
        var that = this;
        arr.forEach(function(e){
            that.messageList.push(e);
        });
    },
    setNum:function(num){
        this.messageNum=num;
    }
});
回到顶部