最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Deep Cloning Backbone.js Models - Stack Overflow

programmeradmin0浏览0评论

I am working in jquery with backbone.js and running into the case where i need to duplicate models, but i need to do a deep copy on them so no references exist between the copies. Models can have other models as attributes. Models can have anon functions as attributes.

So i'm working on creating an algorithm that will deep clone most backbone models. I’m expecting that all bindings should be removed (for the new instance) during this copy so I’m not worried about trying to keep them.

Goals:

  • Able to duplicate all simple variable (String, Int, float, etc) and store it into the new model, as the same name.
    • Done, using toJSON to create a new JSON object which can be passed to set(). This object only contains simple attributes, i.e. does not include attributes assigned to functions or other models.
  • Able to duplicate the anon functions some variables will be assigned to, without knowing function/attribute names beforehand.
    • If I know the name of the attribute which is assigned to a function I can copy it. But if the model is new or unknown I don’t have that information.
  • If an attribute is another backbone model, call the deep copy algorithm recursively on that attribute.
    • Not able to check if an attribute is a backbone model with native backbone methods, looking for a work around.

The simplified version of what I currently have is below:

/**
 * 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;
}

Any help or insight you can give would be greatly appreciated. Thanks!

I am working in jquery with backbone.js and running into the case where i need to duplicate models, but i need to do a deep copy on them so no references exist between the copies. Models can have other models as attributes. Models can have anon functions as attributes.

So i'm working on creating an algorithm that will deep clone most backbone models. I’m expecting that all bindings should be removed (for the new instance) during this copy so I’m not worried about trying to keep them.

Goals:

  • Able to duplicate all simple variable (String, Int, float, etc) and store it into the new model, as the same name.
    • Done, using toJSON to create a new JSON object which can be passed to set(). This object only contains simple attributes, i.e. does not include attributes assigned to functions or other models.
  • Able to duplicate the anon functions some variables will be assigned to, without knowing function/attribute names beforehand.
    • If I know the name of the attribute which is assigned to a function I can copy it. But if the model is new or unknown I don’t have that information.
  • If an attribute is another backbone model, call the deep copy algorithm recursively on that attribute.
    • Not able to check if an attribute is a backbone model with native backbone methods, looking for a work around.

The simplified version of what I currently have is below:

/**
 * 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;
}

Any help or insight you can give would be greatly appreciated. Thanks!

Share Improve this question asked Aug 3, 2012 at 16:06 Daniel GradinjanDaniel Gradinjan 1191 gold badge1 silver badge8 bronze badges 6
  • 1 out of curiosity why would you need to deep copy functions? – WickyNilliams Commented Aug 3, 2012 at 16:32
  • you cannot really deep-copy functions: inside saved state of closures is essentially opaque. Example: function(y) { var x=y; return function() { x++; console.log(x); }; }. – tucuxi Commented Aug 3, 2012 at 16:44
  • Hmmm... underscore's extend will copy both static properties and methods and everything on the prototype from one object to another. You can do this at definition or at run time. But I'm also curious as to why you want to do this because essentially what you're describing is inheritance. – Brendan Delumpa Commented Aug 3, 2012 at 16:56
  • Ok, i guess i misunderstood the meaning of copying functions. As long as the new model has access to the same functions as the old one, and will not clash variables between the two, i'm good. – Daniel Gradinjan Commented Aug 3, 2012 at 17:34
  • Ok, the thing is, i need to have two instances of the same object. One that is bound to the UI. And one for a process done in the background. Any changes i need done on this background model i do not want reflected on the UI until after the process is done. And sometimes not even then. Two completely different instances are needed, just with the same information inside. – Daniel Gradinjan Commented Aug 3, 2012 at 17:36
 |  Show 1 more comment

2 Answers 2

Reset to default 11

jQuery's extend method allows you to simply copy object properties from one to another.

Here's a contrived, but illustrative example. It even shows why you would not need to "deep" copy functions!

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();

Here's a fiddle for your convenience: http://jsfiddle.net/S6p3F/3/

Running this code you will see that someObj and deepCopy are identical in structure but distinct objects.

As you can see, deep copying of functions is not required as the this reference is bound to whatever object the function is applied to. This is becausein javascript, calling a function as deepCopy.f() is functionally equivalent to deepCopy.f.call(deepCopy). A more illustrative example:

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

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

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

And a fiddle: http://jsfiddle.net/S6p3F/2/

If you are using Lo-Dash as Underscore drop-in replacement, you can also use _.cloneDeep

var newModel = new MyModel(_.cloneDeep(oldModel.toJSON());
发布评论

评论列表(0)

  1. 暂无评论