Copying array by value in JavaScript
When copying an array in JavaScript to another array:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
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?
Use this:
var newArray = oldArray.slice();
Basically, the slice() operation clones the array and returns the reference to the 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)
var booleanLiteral = true;
var numberLiteral = 1;
var stringLiteral = 'true';
// Literal structures (type2)
var arrayLiteral = [];
var objectLiteral = {};
// Prototypes (type3)
var booleanPrototype = new Bool(true);
var numberPrototype = new Number(1);
var stringPrototype = new String('true');
var arrayPrototype = new Array();
var objectPrototype = new Object(); # or "new function () {}"
From these elements we can create three types of arrays.
// 1) Array of literal-values (boolean, number, string)
var type1 = [true, 1, "true"];
// 2) Array of literal-structures (array, object)
var type2 = [[], {}];
// 3) Array of prototype-objects (function)
var 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.
Array of literal-values (type1)
The myArray.splice(0)
, myArray.slice()
, and myArray.concat()
techniques can be used to deep copy arrays with literal values (boolean, number, and string) only; where Slice has higher performance than Concat (http://jsperf.com/duplicate-array-slice-vs-concat/3).
Array of literal-values (type1) and literal-structures (type2)
The JSON.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 jQuery $.extend(myArray)
technique can be used to deep-copy all array-types. Libraries like Underscore and Lo-dash offer similar deep-copy functions to jQuery $.extend()
, yet have lower performance. More surprisingly, $.extend()
has higher performance than the JSON.parse(JSON.stringify(myArray))
technique http://jsperf.com/js-deep-copy/15.
And for those developers that shy away from third-party libraries (like jQuery), you can use the following custom function; which has higher performance than $.extend, and deep-copies all arrays.
function copy(o) {
var output, v, key;
output = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
output[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
}
return output;
}
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
has the highest performance.
// Highest performance for deep copying literal values
arr2 = arr1.slice();
// Any of these techniques will deep copy literal values as well,
// but with lower performance.
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above
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.
下一篇: 在JavaScript中按值复制数组