为什么Backbone.View对象仍然留在内存中?

时间:2013-05-16 17:54:01

标签: javascript backbone.js underscore.js javascript-framework

我有简单的视图,显示对话框。

Backbone.View.prototype.completeRemove = function(){
    this.undelegateEvents();
    this.remove();
    delete this.$el;
    delete this.el;
    console.log('completely removed')
}

MdApp.dialogBox = Backbone.View.extend({

    defaults: {
        text: __('No text provided'),
        buttonText: __('Ok'),
        callback: function(){
            return null;
        },
        el: $('#app-panel'),
        type: 'error',
        cancellable: false,
        cancelText: __('No'),
        picture: pic('default')
    },

    el: '<div class="dialog-box">',

    template: _.template($('#dialog-box-template').html()),

    events: {
        'click .confirm' : 'confirm',
        'click .cancel' : 'cancel'
    },

    initialize: function(){
        this.model = _.extend(this.defaults, this.model);
        this.render();
    },

    render: function(){
        var model = this.model;
        this.$el.html(this.template(model));
        model.el.append(this.el);
    },

    confirm: function(){
        var model = this.model;
        var view = this;
        this.completeRemove();
        model.callback();
    },

    cancel: function(){
        this.completeRemove();
    }
});

它有自己的默认值。每次我初始化新对话框时,它的值在每次对话框调用之间都会持续存在。例如,当我第一次调用对话框时:

new MdApp.dialogBox({model:{
        text: __('Do you really wanna delete this?'),
        buttonText: __('Unfortunately yes'),
        callback: function(){
            //some callback
        },
        cancellable: true,
        cancelText: __('No'),
        picture: pic('confirm delete')
    }});

之后,我正在调用另一个没有cancellable属性的对话框,因此它应该使用默认值(false),但它仍然是正确的。这适用于所有其他财产。为什么会这样?

1 个答案:

答案 0 :(得分:2)

来自fine manual

  

延伸 _.extend(destination, *sources)

     

来源对象中的所有属性复制到目标对象,然后返回目标对象。

这意味着_.extend(o, ...)会修改o。所以当你这样做时:

this.model = _.extend(this.defaults, this.model);

你实际上是这样做的:

for(k in this.model)
    this.defaults[k] = this.model[k];
this.model = this.defaults;

defaults已附加到原型中,因此您实际上正在更改defaults的每个实例共享的MdApp.dialogBox。这就是为什么你最终会遇到粘性属性:你将所有不同的this.model合并到视图原型的defaults上。

你可以这样做:

// Merge into an empty object to avoid altering this.defaults
this.model = _.extend({}, this.defaults, this.model);

或者您可以使用_.defaults代替_.extend

  

默认 _.defaults(object, *defaults)

     

使用默认值对象中的值填充对象中的空和未定义属性,然后返回对象。一旦财产被填满,进一步的违约将无效。

所以你可以这样做:

_(this.model).defaults(this.defaults);

这将改变this.model就地,因此您的视图将假设它完全拥有this.model并且没有任何外部引用该对象。