深度克隆Backbone.js模型

时间:2012-08-03 16:06:10

标签: javascript jquery jquery-mobile backbone.js

我正在使用backbone.js在jquery中工作并遇到需要复制模型的情况,但我需要对它们进行深层复制,因此副本之间不存在引用。模型可以将其他模型作为属性。模型可以将anon函数作为属性。

所以我正在努力创建一种能够深度克隆大多数骨干模型的算法。我希望在这个副本中应该删除所有绑定(对于新实例),所以我不担心试图保留它们。

目标:

  • 能够复制所有简单变量(String,Int,float等)并将其存储到新模型中,作为相同的名称。
    • 完成,使用toJSON创建一个可以传递给set()的新JSON对象。该对象仅包含简单属性,即不包括分配给函数或其他模型的属性。
  • 能够在不事先知道功能/属性名称的情况下复制将分配一些变量的anon函数。
    • 如果我知道分配给函数的属性的名称,我可以复制它。但如果模型是新的或未知的,我没有这些信息。
  • 如果属性是另一个骨干模型,则在该属性上递归调用深层复制算法。
    • 无法检查属性是否是具有本机骨干方法的骨干模型,正在寻找解决方法。

我目前拥有的简化版本如下:

/**
 * Performs a deep copy of a backbone.js model
 * All bindings for the copy are lost
 * @param orgModel - the original model to copy
 */
function deepCopyModel(orgModel)
{   
    var dupModel = Backbone.Model.extend({});

    var orgAttributes= orgModel.toJSON();

    var keepAttr=_.keys(orgAttributes);
    //remove any special cases
    keepAttr=_.without( keepAttr , 'specialCase1', 'specialCase2' );
    //or keepAttr=_.difference(keepAttr, ['specialCase1', 'specialCase2'] );

    //remove undefined values
    keepAttr=_.filter(keepAttr,function(key) {
        return ( typeof(attributes[key])!="undefined" );
    });
    //grab the resulting list of attributes after filtering
    var result=_.pick(attributes,keepAttr);
    //assign attributes to the copy using set
    dupModel.set(result);

    //TODO: Implement deep copy of functions

    //TODO: Implement deep copy of inner models

        return dupModel;
}

非常感谢您提供的任何帮助或见解。谢谢!

2 个答案:

答案 0 :(得分:11)

jQuery的extend方法允许您简单地将对象属性从一个复制到另一个。

这是一个人为但又说明性的例子。它甚至可以说明为什么你不需要“深度”复制功能!

var someObj = {
    a : "a",
    b : 12345,
    c : {
        d : "d",
        e : "e"
    },
    f : function() {
        alert(this.a);
    }
};

//copy from original to new empty object
var deepCopy = $.extend(true, {}, someObj);

deepCopy.a = "deepCopy.a";
deepCopy.c.d = "deepCopy.c.d";

alert("someObj is not affected when deep copying: " + someObj.c.d);
alert("deepCopy is entirely distinct when deep copying: " + deepCopy.c.d);

deepCopy.f();    
someObj.f();

为方便起见,这是一个小提琴:http://jsfiddle.net/S6p3F/3/

运行此代码,您会发现someObjdeepCopy在结构上是相同的,但不同的对象。

如您所见,不需要深层复制函数,因为this引用绑定到函数所应用的任何对象。这是因为在javascript中,将函数调用为deepCopy.f()在功能上等同于deepCopy.f.call(deepCopy)。一个更具说明性的例子:

function someFunction() {
    alert(this.someProperty);
}

var a = {
        someProperty: "a's property"
    },
    b = {
        someProperty: "b's property"
    };

someFunction.call(a);
someFunction.call(b);

小提琴:http://jsfiddle.net/S6p3F/2/

答案 1 :(得分:4)

如果您使用Lo-Dash作为Underscore插件替代品,您还可以使用_.cloneDeep

var newModel = new MyModel(_.cloneDeep(oldModel.toJSON());