5

I have an array example fruit . I'd like to copy it as array fruits2, without keeping reference.

As in the following example reference is kept so fruits is modified.


var fruit = function (name){
    this.name = name;
}
var fruits = [];
fruits.push(new fruit('apple'));
fruits.push(new fruit('banana'));
fruits.push(new fruit('orange'));

var fruits2 = fruits;
fruits2.length = 0;
console.log(fruits);

http://jsfiddle.net/vkdqur82/


Using JSON.stringify and JSON.parse does the trick but the objects in fruits2 are not any longer of type fruit but are of general type object

var temp = JSON.stringify(fruits);
var fruits2 = JSON.parse(temp);

I would like to know an alternative approach which would keep inner object of fruit.

6
  • using jquery: jsfiddle.net/vkdqur82/4 Commented Sep 11, 2014 at 20:49
  • related using jquery: stackoverflow.com/questions/16512773/… Commented Sep 11, 2014 at 20:50
  • oranlooney.com/deep-copy-javascript Commented Sep 11, 2014 at 20:55
  • 1
    here is a method using Object.setPrototypeOf() to create new objects, not use JSON, not re-invoke Constructors, but still keep your custom Constructor's and the inherited methods, without promoting everything to own properties or iterating: jsfiddle.net/rndme/x3tz5kzc (only works in newer browsers, but it's the best solution) Commented Sep 11, 2014 at 22:29
  • @dandavis thanks for sharing, I am just wondering about cross browser compatibility as Object.setPrototypeOf() is Harmony (ECMAScript 6) Commented Sep 12, 2014 at 5:43

3 Answers 3

10

Use slice: var fruits2 = fruits.slice(); should do it.

Your jsFiddle, modified

See also: MDN

**Edit. I was a bit lazy, let's correct my answer to make up for that.

For an Array of just values slice is perfect. For an Array of objects or arrays or a mix of values/objects/arrays, the Array and Object elements of the Array to clone need cloning too. Otherwise they will be references to the original arrays or objects (so: not copies) and a change of one [of these references of arrays or objects] will be reflected in all 'clones' containing a reference to it.

To clone an Array of Arrays/Objects/mixed values Array.map is your friend. There are several methods to think of:

  1. creating a new instance with old data
    var fruits1 = fruits.map(function(v) {return new Fruit(v.name);});
  2. using JSON
    var fruits2 = fruits.map(function(v) {return JSON.parse(JSON.stringify(v));});
  3. create and use some cloning method
    var fruits3 = fruits.map(function(v) {return cloneObj(v);});

In case 3, a method for cloning could look like:

function cloneObj(obj) {
    function clone(o, curr) {
        for (var l in o){
            if (o[l] instanceof Object) {
                curr[l] = cloneObj(o[l]);
            } else {
                curr[l] = o[l];
            }
        }
        return curr;
    }
    
    return obj instanceof Array 
             ? obj.slice().map( function (v) { return cloneObj(v); } )
             : obj instanceof Object 
               ? clone(obj, {})
               : obj;
}

Using this cloneObj method, Array.map is obsolete.
You can also use var fruitsx = cloneObj(fruits);

The jsFiddle from the link above is modified to demonstrate these methods.

For Array.map, see again MDN

Sign up to request clarification or add additional context in comments.

6 Comments

Or simply, fruits.slice() (with no args).
Yep, the zero was just habit, removed it.
that doesn't clone the object at all, it just makes a new list of the same objects. if you parse(stringify()), changing a new object doesn't affect the old. as coded, changes to old or new will appear in the other. i'm not saying that's a deal-breaker, but it's a huge difference from the JSON-based clone mentioned by the OP
@dandavis iwhat about using jquery for deepcopy... smt like... var fruis2 = $.extend(true, [], fruits) ??
Sorry for my lazyness, I hope my corrected answer will make things more clear. @GibboK: $.extend will keep references to objects within an Array, in other words will not really copy them.
|
2

slice can do the trick.

You can also use .map but .slice is normally faster.

var copy = fruits.map(function(item) {return item});

Hope it helps

Comments

0

You can declare a new array and use concat method, so that you concat all values from your array to the new array. Something like this:

var x = ["a","b"];
var a = [];
a = a.concat(x);
console.log(a);

I edited my poor answer.

Best regards.

2 Comments

This doesn't look like an answer. It should be a comment.
Sorry, I answered from my mobile phone. It's first time I use it. Let's se if i can delete it. Thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.