Создает ли распространение неглубокую копию?

#javascript

#typescript #ecmascript-6 #глубокая копия #неглубокая копия

Вопрос:

Согласно приведенному здесь примеру,

 let first:number[] = [1, 2];
let second:number[] = [3, 4];

let both_plus:number[] = [0, ...first, ...second, 5];
console.log(`both_plus is ${both_plus}`);
first[0] = 20;
console.log(`first is ${first}`);
console.log(`both_plus is ${both_plus}`);
both_plus[1]=30;
console.log(`first is ${first}`);
console.log(`both_plus is ${both_plus}`);
  

Распространение показывает глубокую копию, потому что все три массива имеют собственные дубликаты, основанные на приведенных ниже выходных данных:

 both_plus is 0,1,2,3,4,5
first is 20,2
both_plus is 0,1,2,3,4,5
first is 20,2
both_plus is 0,30,2,3,4,5
  

В документации говорится: Распространение создает неглубокую копию first и second . Как я это понимаю?

Комментарии:

1. Это то же самое, что [0, 1, 2, 3, 4, 5] . Вы не можете точно сказать, является ли копия глубокой, если все, что у вас есть, — это примитивы.

2. Нет, синтаксис распространения ничего не создает и не копирует. Это литерал массива, который создает новый массив.

Ответ №1:

В вашем случае неглубокая копия и глубокая копия — это одно и то же. Для массива, содержащего только примитивы, они всегда будут идентичны. Вы заметите разницу, только когда ваш массив будет содержать другие объекты.

Javascript передается по значению, поэтому, когда массив копируется неглубоко (например, с помощью spread), каждое значение из исходного массива копируется в новый массив. В случае примитива значение копируется напрямую, и внесенные в него изменения не влияют на оригинал.

Однако, когда массив содержит объекты, каждое значение само по себе является ссылкой на что-то другое. Таким образом, даже если ссылка была скопирована в новый массив, она по-прежнему указывает на то же самое, что и ссылка в исходном массиве. Таким образом, хотя изменение нового массива не изменит оригинал, изменение элементов массива повлияет на оригинал.

Вот пример:

 const objArray = [{foo: "bar"}];
const shallowCopy = [...objArray];

// Changing the array itself does not change the orignal. Note the
// original still only has one item, but the copy has two:
shallowCopy.push({foo: "baz"});
console.log("objArray after push:", objArray);
console.log("shallowCopy after push:", shallowCopy);

// However, since shallowCopy[0] is a reference pointing to the same object
// as objArray[0], mutating either will change the other:
shallowCopy[0].foo = "something else";
console.log("objArray after mutation:", objArray);
console.log("shallowCopy after mutation:", shallowCopy);  

Ответ №2:

Неглубокая копия означает, что все элементы из first и second просто добавляются в новый массив, новую копию. Глубокое копирование будет означать, что все элементы из first и second сначала копируются, а затем добавляются в новый массив.

Различие заключается в том, копируются ли сами элементы в новый объект перед добавлением в новый массив.

Используя примитивы, такие как числа, на самом деле невозможно проиллюстрировать разницу, но если вы используете объекты, разница довольно очевидна.

Допустим, у вас есть что-то вроде этого:

 let first = [{foo: 'bar'}];
let second = [{fizz: 'buzz'}];
let both = [...first, ...second];
  

Поскольку распространение приводит к неглубокой копии, можно ожидать, что соответствующие объекты пройдут тест на равенство:

 first[0] === both[0]; // true
second[0] === both[1]; // true
  

Но если распространение привело к глубокой копии, вы ожидаете, что тест на равенство завершится неудачей:

 first[0] === both[0]; // false
second[0] === both[1]; // false
  

Комментарии:

1. На моей машине результаты, оцененные в first[0] === both[0]; // false , second[0] === both[1]; // true

Ответ №3:

Распространение приводит к неглубокой копии

 const a = [{x: 1}, {y: 1}];
const b = a;

const c = [...a, ...b];
console.log(c); // [{x: 1}, {y: 1}, {x: 1}, {y: 1}]

a[1]['y'] = 5;
console.log(c); // [{x: 1}, {y: 5}, {x: 1}, {y: 5}]