не равно массивам, меняющим значения одновременно javascript - PullRequest
0 голосов
/ 29 августа 2018

Пожалуйста, проверьте следующее ...

var arr = [["test", 1], ["test", 3], ["test", 5]]
var otherArr = arr.slice(0) //should be a new array with a copy of arr

Когда я оцениваю arr === otherArr результат равен FALSE .

Когда я делаю следующее, пытаясь изменить первое значение массива:

otherArr[0][1] = otherArr[0][1] + 5;

также изменяет исходный массив (обр)

arr[0][1] === otherArr[0][1] оценивается как ИСТИНА

но arr === otherArr оценивается как FALSE

Пожалуйста, помогите мне понять это, чтобы избежать этого.

Ответы [ 4 ]

0 голосов
/ 30 августа 2018

Это лучше всего объяснить визуально. Представьте arr как следующую диаграмму. На самом деле он состоит из 3 массивов, один из которых ссылается на два других:

arr [     0      ,      1      ]
          |             |
          v             v
      ['test', 1], ['test', 5]

Когда вы сделали otherArr.slice(0), он создает «мелкую копию» - новый массив , но с идентичным содержимым исходному массиву. Это означает, что arr и otherArr являются двумя отдельными массивами, но указывают на одно и то же содержимое. arr[0] - это тот же объект, что и otherArr[0], а arr[1] - это тот же объект, что и otherArr[1]

arr      [     0      ,      1      ]
               |             |
               v             v
           ['test', 1], ['test', 5]
               ^             ^
               |             |
otherArr [     0      ,      1      ]

Теперь к вашим вопросам:

Когда я вычисляю arr === otherArr, результат равен FALSE.

Как упоминалось выше, arr и otherArr - это два разных массива, что приводит к сбою ===. Для не примитивов === проверяет идентичность (то есть это один и тот же объект?). Также обратите внимание, что === и == НЕ являются структурными проверками (т.е. они выглядят одинаково?).

Когда я делаю следующее, пытаясь изменить первое значение массива:

otherArr[0][1] = otherArr[0][1] + 5;

также изменяет исходный массив (обр)

arr[0][1] === otherArr[0][1] evaluates to TRUE

Возвращаясь к нашей диаграмме, вы фактически изменяете содержимое объекта, на который ссылаются оба массива (в данном случае тот, который сейчас ['test', 6]).

arr      [     0      ,      1      ]
               |             |
               v             v
           ['test', 6], ['test', 5]
               ^             ^
               |             |
otherArr [     0      ,      1      ]
0 голосов
/ 29 августа 2018

Это потому, что массивы - это разные объекты из slice()

arr === otherArr // false (different objects)

Но значения, хранящиеся в массивах, являются одинаковыми объектами

 arr[0][1] === otherArr[0][1] 

Если вам не нужно это поведение, вам нужно будет сделать deep copy массива вместо среза.

Вот некоторая информация о deep copy применительно к массивам: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm

0 голосов
/ 29 августа 2018

Проблема

Метод slice () возвращает мелкую копию […]

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

    var arr = [["test", 1], ["test", 3], ["test", 5]]
    
    var otherArr = [...arr[0], ...arr[1], ...arr[2]]
    
    
    otherArr[0][1] = otherArr[0][1] + 5;
    
    console.log(arr)

Метод JSON.parse(JSON.stringify(arr)) является лучшим решением в целом.

0 голосов
/ 29 августа 2018

Когда я оцениваю arr === otherArr результат равен FALSE .

потому что срез не тот же массив.
по сути, это копия содержимого массивов.

Когда я делаю следующее, пытаясь изменить первое значение массива:

otherArr[0][1] = otherArr[0][1] + 5;

также изменяет исходный массив (обр)

arr[0][1] === otherArr[0][1] оценивается как ИСТИНА

, но arr === otherArr оценивается как FALSE

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

вы копируете все содержимое arr в otherArr
но вы не создаете копии объектов, на которые оно ссылается.

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

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

потому что arr просто указывает на массивы. он не содержит их. это ссылки.


пожалуйста, взгляните также на комментарий от Calvin Nunes ниже вашего вопроса:

вы можете создать глубокую копию, сначала преобразовав свой массив в строку json, а затем обратно в массив:
otherArr = JSON.parse(JSON.stringify(arr))

Имейте в виду, что это работает с простыми вещами, но если вы хотите скопировать объекты, которые содержат пользовательские функции и т. Д., Вы можете об этом забыть.
они не будут добавлены в представление json и будут потеряны.

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

вы можете вместо этого рекурсивно скопировать ваш массив.
например, проходя по массиву, если член относится к типу array, проходите по нему тоже.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...