8

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

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

目标:

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

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

/**
 * 执行一个backbone.js 模型的深拷贝
 * 副本的所有绑定都丢失了
 * @param orgModel - 要复制的原始模型
 */
函数 deepCopyModel(orgModel)
{   
    var dupModel = Backbone.Model.extend({});

    var orgAttributes= orgModel.toJSON();

    var keepAttr=_.keys(orgAttributes);
    //删除任何特殊情况
    keepAttr=_.without(keepAttr, 'specialCase1', 'specialCase2');
    //或keepAttr=_.difference(keepAttr, ['specialCase1', 'specialCase2'] );

    //删除未定义的值
    keepAttr=_.filter(keepAttr,function(key) {
        返回 ( typeof(attributes[key])!="undefined" );
    });
    //获取过滤后的属性列表
    变种结果=_.pick(属性,keepAttr);
    //使用set为副本分配属性
    dupModel.set(结果);

    //TODO: 实现函数的深拷贝

    //TODO: 实现内部模型的深拷贝

        返回复制模型;
}

您可以提供的任何帮助或见解将不胜感激。谢谢!

4

2 回答 2

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/

someObj运行此代码,您将看到deepCopy结构相同但对象不同。

如您所见,不需要对函数进行深度复制,因为this引用绑定到函数应用到的任何对象。这是因为在 javascript 中,调用函数 asdeepCopy.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/

于 2012-08-03T16:37:36.693 回答
4

如果你使用Lo-Dash作为 Underscore 的替代品,你也可以使用_.cloneDeep

var newModel = new MyModel(_.cloneDeep(oldModel.toJSON());
于 2013-08-20T08:07:52.757 回答