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.

GibboK
  • 71,848
  • 143
  • 435
  • 658
  • using jquery: http://jsfiddle.net/vkdqur82/4/ – GibboK Sep 11 '14 at 20:49
  • related using jquery: http://stackoverflow.com/questions/16512773/jquery-extendtrue-obj-not-creating-a-deep-copy – GibboK Sep 11 '14 at 20:50
  • http://oranlooney.com/deep-copy-javascript/ – GibboK Sep 11 '14 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: http://jsfiddle.net/rndme/x3tz5kzc/ (only works in newer browsers, but it's the best solution) – dandavis Sep 11 '14 at 22:29
  • @dandavis thanks for sharing, I am just wondering about cross browser compatibility as Object.setPrototypeOf() is Harmony (ECMAScript 6) – GibboK Sep 12 '14 at 05:43
  • i know it works for Chrome and Firefox, and you can fake it anywhere with _ _proto_ _ support – dandavis Sep 12 '14 at 14:15

3 Answers3

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

KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • 1
    Or simply, `fruits.slice()` (with no args). – php-dev Sep 11 '14 at 19:41
  • Yep, the zero was just habit, removed it. – KooiInc Sep 11 '14 at 20:11
  • 1
    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 Sep 11 '14 at 20:27
  • @dandavis iwhat about using jquery for deepcopy... smt like... var fruis2 = $.extend(true, [], fruits) ?? – GibboK Sep 11 '14 at 20:36
  • @KooiInc but using the MAP method together with JSON methods will create the result with general 'objects', where instead I what keep the specific type of 'fruit' – GibboK Sep 11 '14 at 20:39
  • 1
    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. – KooiInc Sep 11 '14 at 22:01
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

php-dev
  • 6,998
  • 4
  • 24
  • 38
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.

javifm
  • 705
  • 4
  • 9
  • 20