简体   繁体   中英

Is there a way to reassign an argument within a function, and have it also affect the calling scope?

What I am trying to do is build a clone() function for Javascript objects. As you know the lack of native functionality for this in Javascript can be a pain. I have a great method to do it, but usability wise, it is awkward. Here is the function so far:

function clone(objectToClone) {
    var myClone = function() {};
    myClone.prototype = objectToClone;
    return [
        new myClone(),
        new myClone()
    ];
}

As you can see, currently I just return an array with both clones. This makes the usage look something like this:

// usage
var bar = new foo();
bar = clone(bar); // forks bar into two separate copies of bar (awkward)
// bar[0] is now clone 1
// bar[1] is now clone 2

What I would like to do, is be able to do something like the following:

function clone(objectToClone) {
    var myClone = function() {};
    myClone.prototype = objectToClone;
    objectToClone = new myClone(); // somehow magically?
    return new myClone();
}

// usage
var bar = new foo();
var baz = clone(bar); // returns a copy, and bar is now one of the copies as well.
// bar is now clone 1
// baz is now clone 2

Unfortunately this does not work, since assigning the argument does not affect the calling scope. I was hoping that someone might be able to help think up some js trickery that would allow me to use the function in the desired manor however. Any ideas are greatly appreciated.

You could have your clone function return the copy, while leaving the original alone.

If this is impossible or impractical for some reason, that is the best you can do:

var bar = new foo();
var clones = clone(bar);
bar = clones[0];
barCopy = clones[1];

Unless you resort to incredibly inelegant eval trickery.

I think what you really want is to just return new myClone() and never use bar . This actually makes things a bit more elegant (you can call it bar_template or something if desired), since you can now clone the original template.

You wanted me to explain my comment, here you go:

function replaceClones(){
    for(var i = 0; i < arguments.length; i++){
        var varName = arguments[i];
        this[varName] = getClone(this[varName]);
    }    
}

function getClone(obj){
    var Clone = function(){};
    Clone.prototype = obj;
    return new Clone();
}

replaceClones("varA","varB");

If you want another scope, just use

replaceClones.call(newScope,"varA","varB");

To get your desired result, you would need to pass in an object with properties and then modify those properties. That's the best way to get a reference in javascript that allows you to change the original. You cannot change the original when it's just passed as an ordinary function argument. Javascript doesn't have those types of references.

function clone(holder) {
    var myClone = function() {};
    myClone.prototype = holder.input;
    holder.input = new myClone(); // somehow magically?
    return new myClone();
}

// usage
var holder = {};
var holder.input = new foo();
var holder.output = clone(holder); // returns a copy, and holder.input is now a copy too
// holder.input is now clone 1
// holder.putput is now clone 2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM