Почему изменение массива в 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.

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

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

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

13 57

13 ответов:

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

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

var copyOfArray = array;

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

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

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

это с помощью ... синтаксис распространения.

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

редактировать: Что касается почему из этого, и чтобы ответить на ваш вопрос:

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

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

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

copyOfMyArray действительно просто ссылка на myArray, а не фактическая копия.

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

глоссарий MDN: Mutable

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

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 все дают желаемый результат, кроме конечного (объекта), который, поскольку он копируется по ссылке, также мутирует исходный array[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/

ура

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

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

S.

создайте фильтр исходного массива в 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']

надеюсь, что это помогает.

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

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

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

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

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

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

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;
}

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

например.

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 не будет отражаться на a

массив или объект в 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 (), эти функции создадут новый объект с другой ссылкой. Если вы знаете больше функций для этого, пожалуйста, скажите мне, спасибо!

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

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

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

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

ответ тут

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']

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