3

Using .slice(), I can deep copy a Javascript Array of primitive types, for example:

var arr = [1,2,3,4];
var newArr = arr.slice();
newArr.push(5);
console.log(arr); // [1,2,3,4]
console.log(newArr); // [1,2,3,4,5]

However, If I add a property to arr like so:

arr.prop1 = 5;

and do the same:

var arr = [1,2,3,4];
arr.prop1 = 8;
arr.prop2 = 9;
var newArr = arr.slice();
newArr.push(5);
console.log(arr); // [1, 2, 3, 4, prop1: 9, prop2: 8]
console.log(newArr); //  [1, 2, 3, 4, 5]

The property values do not carry over to newArr

I have considered not using .slice() and looping over the property values of arr instead, assigning them to newArr, using :

for (var key in arr) {
  if (arr.hasOwnProperty(key)) {
    newArr[key] = arr[key];
  }
}
console.log(arr); // [1, 2, 3, 4, prop1: 9, prop2: 8]
console.log(newArr); //  [1, 2, 3, 4, 5, prop1: 9, prop2: 8]

Is this going to be the quickest way to deep copy these arrays with properties? Is there in easier or cleaner way I can do this using .slice() or another array method? I am doing this operation tens of thousands of times and want it to be as clean and efficient as possible

8
  • 2
    Why you're using an array if you should be using an object instead? Commented Dec 29, 2016 at 8:54
  • Whether this is good enough depends on whether you are expecting prototyped properties/methods to be available in newArr. Commented Dec 29, 2016 at 8:56
  • @Andreas I am using an array because I want to be able to maniputate the array data [1,2,3,4] using array methods. It is already part of an object and currently gets copied using .slice(). I think that if I nest the array inside an object inside another object, my code gets messy and is harder to maintain, I also think that I am slowing down in terms of processing. Is my reasoning correct? Commented Dec 29, 2016 at 9:02
  • @Phylogenesis I would like the properties to be available in newArr I don't need any methods to be copied. I would just like to copy primitive types over Commented Dec 29, 2016 at 9:03
  • @Andreas could you tell me how you would approach this problem using an object and what the benefits would be? Commented Dec 29, 2016 at 9:18

2 Answers 2

2

You are trying to mix an array and object(to make an array behave like an object).
JavaScript array has numeric indexed items.
JavaScript object has string indexed items.

Arrays have a length property that tells how many items are in the array and is automatically updated when you add or remove items to the array.
But ...

var arr = [1,2,3,4], newArr = arr.slice();
arr.prop1 = 7;

console.log(arr.length);

The output is 4, though you would expect it to be 5.
But arr.prop1 = 7 does not actually add to the array.
Setting a string parameter adds to the underlying object.
The length property is only modified when you add an item to the array, not the underlying object.
The expression newArr = arr.slice() assigns a new array to newArr, so it remains an array and behaves like a pure array.

The property values do not carry over to newArr

If you still want to proceed using mixed numeric/string indexed sequences, cloning them, try using Object.assign() function. This should be the easiest way for your case:

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

console.log(Object.assign(newArr, arr));

The output:

[1, 2, 3, 4, prop1: 7]

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

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

2 Comments

@RomanPekerhrest I really like this answer, although the reason I want to attach properties to this array is so that I don't have to .filter() the array over and over to splice() values from it, I can use the properties as a sort of meta data so I can just splice() using index values. This means that having the length unaltered by the properties is exactly why I want them. I will have a look into object.assign() it looks very promising. Thank you!
So have var myObj = { props: {prop1:7}, arr:[1,2,3,4]}
2

How about using Object.create(proto)

var arr = [1,2,3,4];
arr.prop1 = 8;
arr.prop2 = 9;
var newArr = Object.create(arr);

newArr.prop1 = 12;
console.log(arr.prop1) // 8
console.log(newArr.prop1) // 12

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

1 Comment

np. it looks like it might have to be shimmed with __proto__ for < Opera 11.60, but nobody uses an old version of Opera for anything but testing. good luck. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.