В Javascript методы глубокого копирования зависят от элементов в массиве. Давайте начнем там.
Три типа элементов
Элементами могут быть: литеральные значения, литеральные структуры или прототипы.
// 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 () {}"
Из этих элементов мы можем создать три типа массивов.
// 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 () {}];
Методы глубокого копирования зависят от трех типов массивов
На основе типов элементов в массиве мы можем использовать различные методы для глубокого копирования.
Массив литеральных значений (тип1)
Методы [...myArray]
, myArray.splice(0)
, myArray.slice()
и myArray.concat()
могут использоваться для глубокого копирования массивов только с литеральными значениями (булевыми, числовыми и строковыми); где оператор Spread [...myArray]
имеет наилучшую производительность (https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat).
Массив литеральных значений (тип1) и литеральных структур (тип2)
Техника JSON.parse(JSON.stringify(myArray))
может использоваться для глубокого копирования литеральных значений (логические, числа, строки) и литеральных структур (массив, объект), но не объектов-прототипов.
Все массивы (тип1, тип2, тип3)
Техника jQuery $.extend(myArray)
может использоваться для глубокого копирования всех типов массивов. Такие библиотеки, как Underscore и Lo-dash предлагают функции глубокого копирования, аналогичные jQuery $.extend()
, но при этом имеют более низкую производительность. Что еще более удивительно, $.extend()
имеет более высокую производительность, чем JSON.parse(JSON.stringify(myArray))
метод http://jsperf.com/js-deep-copy/15.
И для тех разработчиков, которые избегают сторонних библиотек (таких как jQuery), вы можете использовать следующую пользовательскую функцию; которая имеет более высокую производительность, чем $ .extend, и копирует все массивы.
function copy(aObject) {
if (!aObject) {
return aObject;
}
let v;
let bObject = Array.isArray(aObject) ? [] : {};
for (const k in aObject) {
v = aObject[k];
bObject[k] = (typeof v === "object") ? copy(v) : v;
}
return bObject;
}
Итак, чтобы ответить на вопрос ...
Вопрос
var arr1 = ['a','b','c'];
var arr2 = arr1;
Я понял, что arr2 относится к тому же массиву, что и arr1, а не к
новый, независимый массив. Как я могу скопировать массив, чтобы получить два
независимые массивы?
Ответ
Поскольку arr1
- это массив литеральных значений (логические, числовые или строковые), вы можете использовать любую методику глубокого копирования, рассмотренную выше, где оператор распространения ...
имеет наибольшую производительность.
// Highest performance for deep copying literal values
arr2 = [...arr1];
// Any of these techniques will deep copy literal values as well,
// but with lower performance.
arr2 = arr1.slice();
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