Подтвердить что ты не робот

Почему изменение массива в JavaScript влияет на копии массива?

Я написал следующий JavaScript:

var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray;
copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['b','c']
alert(copyOfMyArray); // alerts ['b','c']

var myNumber = 5;
var copyOfMyNumber = myNumber;
copyOfMyNumber = copyOfMyNumber - 1;
alert(myNumber); // alerts 5
alert(copyOfMyNumber); // alerts 4        

Этот код объявляет переменную myArray и устанавливает ее в значение массива. Затем он объявляет вторую переменную copyOfMyArray и устанавливает ее в myArray. Он выполняет операцию на copyOfMyArray, а затем предупреждает как myArray, так и copyOfMyArray. Так или иначе, когда я выполняю операцию на copyOfMyArray, кажется, что та же операция выполняется на myArray.

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

В чем разница между массивом и числом в JavaScript, который, по-видимому, меняет массив, изменяет значение копии массива, где, когда изменение числа не изменяет значение копии числа?

Я предполагаю, что по какой-то причине массив ссылается по ссылке и номеру по значению, но почему? Как я могу узнать, какое поведение ожидать от других объектов?

4b9b3361

Ответ 1

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

Ваше сравнение с примером номера неверно. Вы назначаете новое значение copyOfMyNumber. Если вы присвойте новое значение copyOfMyArray, он не изменит значение myArray.

Вы можете создать копию массива с помощью slice [docs]:

var copyOfMyArray = myArray.slice(0);

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

Ответ 2

Ну, единственный возможный ответ - и правильный; что вы на самом деле не копируете массив. Когда вы пишете

var copyOfArray = array;

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

Ответ 3

Таким образом, все здесь проделали большую работу, объясняя , почему это происходит - я просто хотел подвести черту и рассказать, как мне удалось это исправить - довольно легко:

thingArray = ['first_thing', 'second_thing', 'third_thing']
function removeFirstThingAndPreserveArray(){
  var copyOfThingArray = [...thingArray]
  copyOfThingArray.shift();
  return copyOfThingArray;
}

Это использует... синтаксис распространения.

Распространение источника синтаксиса

ОБНОВЛЕНИЕ: Как, почему это, и ответить на ваш вопрос:

В чем разница между массивом и числом в JavaScript в том, что изменение массива, по-видимому, приводит к изменению значения копии массива, тогда как при изменении числа не изменяется значение копии числа?

Ответ заключается в том, что в JavaScript массивы и объекты являются изменяемыми, а строки и числа и другие примитивы неизменными. Когда мы делаем назначение, как:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;

copyOfMyArray - это просто ссылка на myArray, а не фактическая копия.

Я бы порекомендовал эту статью Что такое неизменяемые и изменяемые структуры данных?, чтобы углубиться в тему.

Глоссарий MDN: Изменчивый

Ответ 4

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

const objectThatIWantToClone = { foo: 'bar'};
const clone = JSON.parse(JSON.stringify(objectThatIWantToClone));

Стригируя его, мы создаем его неизменную копию, которую затем можем преобразовать обратно в JSON.

https://codepen.io/Buts/pen/zWdVyv

Ответ 5

Объекты клонирования -

A loop / array.push дает аналогичный результат для array.slice(0) или array.clone(). Значения передаются по ссылке, но поскольку большинство примитивных типов данных неизменяемы, последующие операции дают желаемый результат - "клон". Это, конечно, не относится к объектам и массивам, которые позволяют изменять исходную ссылку (они являются изменяемыми типами).

Возьмем следующий пример:

const originalArray = [1, 'a', false, {foor: 'bar'}]
const newArray = [];

originalArray.forEach((v, i) => {
    newArray.push(originalArray[i]);
});

newArray[0] = newArray[0] + 1;
newArray[1] = 'b';
newArray[2] = true;
newArray[3] = Object.assign(newArray[3], {bar: 'foo'});

Операции, выполняемые на индексах newArray, производят желаемый результат, за исключением конечного (объекта), который, поскольку он копируется по ссылке, также будет мутировать исходный массив [3].

https://jsfiddle.net/7ajz2m6w/

Обратите внимание, что array.slice(0) and array.clone() страдает от этого же ограничения.

Один из способов решения этой проблемы - эффективно клонировать объект во время последовательности нажатия:

originalArray.forEach((v, i) => {
    const val = (typeof v === 'object') ? Object.assign({}, v) : v;
    newArray.push(val);
});

https://jsfiddle.net/e5hmnjp0/

веселит

Ответ 6

В JS оператор "=" скопирует указатель на область памяти массива. Если вы хотите скопировать массив в другой, вы должны использовать функцию Clone.

Для целых чисел разные, потому что они являются примитивными типами.

S.

Ответ 7

Все копируется по ссылке, кроме примитивных типов данных (строки и числа IIRC).

Ответ 8

Создайте фильтр исходного массива в arrayCopy. Так что изменения в новом массиве не будут влиять на исходный массив.

var myArray = ['a', 'b', 'c'];
var arrayCopy = myArray.filter(function(f){return f;})
arrayCopy.splice(0, 1);
alert(myArray); // alerts ['a','b','c']
alert(arrayCopy); // alerts ['b','c']

Надеюсь, что это поможет.

Ответ 9

У вас нет никаких копий.
У вас есть несколько переменных, содержащих один и тот же массив.

Аналогично, у вас есть несколько переменных, содержащих один и тот же номер.

Когда вы пишете copyOfMyNumber = ..., вы помещаете новое число в переменную.
Это похоже на запись copyOfMyArray = ....

Когда вы пишете copyOfMyArray.splice, вы изменяете исходный массив.
Это невозможно с числами, потому что числа неизменяемы и не могут быть изменены,

Ответ 10

Вы можете добавить некоторую обработку ошибок в зависимости от ваших случаев и использовать что-то похожее на следующую функцию для решения проблемы. Прокомментируйте любые ошибки/проблемы/идеи эффективности.

function CopyAnArray (ari1) {
   var mxx4 = [];
   for (var i=0;i<ari1.length;i++) {
      var nads2 = [];
      for (var j=0;j<ari1[0].length;j++) {
         nads2.push(ari1[i][j]);
      }
      mxx4.push(nads2);
   }
   return mxx4;
}

Ответ 11

Другой подход для копирования массива во временную переменную может быть типизированием/изменением вашего массива в строку, а затем его извлечением.

Например

var a = [1,2,3];
typeof(a) (this will give "object")
var b = JSON.stringify(a);
typeof(b) (this will give "string");
b = JSON.parse(b);
typeOf(b) (this will give "object")

и теперь chnage в значении b не будет отражаться на

Ответ 12

Массив, или объект в javascript всегда содержит одну и ту же ссылку, если вы не клонируете или не копируете. Вот пример:

http://plnkr.co/edit/Bqvsiddke27w9nLwYhcl?p=preview

// for showing that objects in javascript shares the same reference

var obj = {
  "name": "a"
}

var arr = [];

//we push the same object
arr.push(obj);
arr.push(obj);

//if we change the value for one object
arr[0].name = "b";

//the other object also changes
alert(arr[1].name);

Для клонирования объектов мы можем использовать .clone() в jquery и angular.copy(), эти функции создадут новый объект с другой ссылкой. Если вы знаете больше функций для этого, скажите, пожалуйста, спасибо!

Ответ 13

Ваш ответ здесь

var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray.slice();

В принципе, операция slice() клонирует массив и возвращает неглубокую копию.

copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['a', 'b', 'c']
alert(copyOfMyArray); // alerts ['b','c']

Четкую документацию можно найти по следующей ссылке: Array.prototype.slice()

Ответ 14

      var myArray = ['a', 'b', 'c'];
      var copyOfMyArray = JSON.parse(JSON.stringify(myArray));
      copyOfMyArray.splice(0,1);
      
      console.log('orginal Array',myArray)
      console.log('After Splic of copyOfMyArray',copyOfMyArray);
      //If not using the JSON.parse(JSON.stringify (array)) at the time of assign the array change of the one array will affect another because of the reference. 

Ответ 15

В JavaScript копирование массивов и объектов изменяет исходные значения, поэтому Deep Copy является решением для этого.

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

JSON.parse и JSON.stringify - лучший и простой способ глубокого копирования. Метод JSON.stringify() преобразует значение JavaScript в строку JSON. Метод JSON.parse() анализирует строку JSON, создавая значение JavaScript или объект, описываемый строкой.

//Глубокий клон

let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0

console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]

Для более подробной информации: читайте здесь

Ответ 16

Проблема с мелким копированием состоит в том, что все объекты не клонируются, вместо этого он получает ссылку. Поэтому array.slice(0) будет нормально работать только с литеральным массивом, но он не будет делать мелкое копирование с массивом объектов. В этом случае один из способов...

var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}];
var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement));  
console.log(clonedArray);
// [{name: 'foo', id: 121}, {name: 'zoo', id: 321}]  // shallow copy