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. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.