Copy array by value
Use this:
let oldArray = [1, 2, 3, 4, 5];
let newArray = oldArray.slice();
console.log({newArray});
Basically, the slice()
operation clones the array and returns a reference to a new array.
Also note that:
For references, strings and numbers (and not the actual object), slice()
copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.
Primitives such as strings and numbers are immutable, so changes to the string or number are impossible.
In Javascript, deep-copy techniques depend on the elements in an array. Let's start there.
Three types of elements
Elements can be: literal values, literal structures, or prototypes.
// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';
// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};
// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}
From these elements we can create three types of arrays.
// 1) Array of literal-values (boolean, number, string)
const type1 = [ true, 1, "true" ];
// 2) Array of literal-structures (array, object)
const type2 = [ [], {} ];
// 3) Array of prototype-objects (function)
const type3 = [ function () {}, function () {} ];
Deep copy techniques depend on the three array types
Based on the types of elements in the array, we can use various techniques to deep copy.
Deep copy techniques
Benchmarks
https://www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison
Array of literal-values (type1)
The[ ...myArray ]
,myArray.splice(0)
,myArray.slice()
, andmyArray.concat()
techniques can be used to deep copy arrays with literal values (boolean, number, and string) only; whereslice()
has the highest performance in Chrome, and spread...
has the highest performance in Firefox.Array of literal-values (type1) and literal-structures (type2)
TheJSON.parse(JSON.stringify(myArray))
technique can be used to deep copy literal values (boolean, number, string) and literal structures (array, object), but not prototype objects.All arrays (type1, type2, type3)
- The Lo-dash
cloneDeep(myArray)
or jQueryextend(true, [], myArray)
techniques can be used to deep-copy all array-types. Where the LodashcloneDeep()
technique has the highest performance. - And for those who avoid third-party libraries, the custom function below will deep-copy all array-types, with lower performance than
cloneDeep()
and higher performance thanextend(true)
.
- The Lo-dash
function copy(aObject) {
// Prevent undefined objects
// if (!aObject) return aObject;
let bObject = Array.isArray(aObject) ? [] : {};
let value;
for (const key in aObject) {
// Prevent self-references to parent object
// if (Object.is(aObject[key], aObject)) continue;
value = aObject[key];
bObject[key] = (typeof value === "object") ? copy(value) : value;
}
return bObject;
}
So to answer the question...
Question
var arr1 = ['a','b','c'];
var arr2 = arr1;
I realized that arr2 refers to the same array as arr1, rather than a new, independent array. How can I copy the array to get two independent arrays?
Answer
Because arr1
is an array of literal values (boolean, number, or string), you can use any deep copy technique discussed above, where slice()
and spread ...
have the highest performance.
arr2 = arr1.slice();
arr2 = [...arr1];
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = copy(arr1); // Custom function needed, and provided above
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = jQuery.extend(true, [], arr1); // jQuery.js needed
No jQuery needed... Working Example
var arr2 = arr1.slice()
This copys the array from the starting position 0
through the end of the array.
It is important to note that it will work as expected for primitive types (string, number, etc.), and to also explain the expected behavior for reference types...
If you have an array of Reference types, say of type Object
. The array will be copied, but both of the arrays will contain references to the same Object
's. So in this case it would seem like the array is copied by reference even though the array is actually copied.
You can use array spreads ...
to copy arrays.
const itemsCopy = [...items];
Also if want to create a new array with the existing one being part of it:
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
Array spreads are now supported in all major browsers but if you need older support use typescript or babel and compile to ES5.
More info on spreads