Почему push локального массива изменяет глобальный массив?

1

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

var globalarray = [1,2,3];

 function test(){
     let localarray = globalarray;
     localarray.push(4);
     console.log(localarray);
     console.log(globalarray);
 }
 setInterval(test, 2000);

Возвращает:

 [1,2,3,4] for both

Мое впечатление было то, что localarray будет копией globalarray. Я увидел еще один ответ, который сказал, чтобы сделать копию массива, которую нужно использовать .slice().reverse(), который кажется обходным путем. Почему он не просто создает новую локальную копию? Есть ли простой и эффективный способ создания локальной копии глобального массива? В противном случае кажется, что создание нескольких мутаций для глобального массива ужасно для производительности.

  • 1
    Оператор присваивания просто присваивает ссылку на существующий массив новой переменной. let localarray = globalarray не будет создавать новый массив и присваивать globalarray. вы можете использовать оператор распространения let localarray = [...globalarray] но имейте в виду, что оператор распространения делает только поверхностное копирование.
  • 0
    Возможный дубликат копирования массива по значению в JavaScript
Теги:

3 ответа

1
Лучший ответ

Причина этого в вашем коде заключается в том, что вы просто говорите своей test функции, globalarray на globalarray с помощью оператора =. Это связано с тем, что в JavaScript назначения переменных не по своей сути "копируют" объекты в новые переменные; это может показаться запутанным, поэтому просто подумайте об операторе = как знаке, указывающем ваш код на местоположение объекта.

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

Причина .slice().reverse() заключается в том, чтобы обойти проблему, которую вы видите. Другой способ, которым вы могли бы это сделать, - использовать let localarray = globalarray.map(e => e) или как это было предложено, используя let localarray = [...globalarray]. Оператор .map принимает функцию, данную ему как первый аргумент, и применяет ее к каждому элементу, а затем сохраняет результат в другом массиве в другом месте, которое не совпадает с globalarray.

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

let localarray = new Array(globalarray.length);
for (let i = 0; i < globalarray.length; i++) {
    localarray[i] = globalarray[i];
}

// localarray can now be freely modified because it does not point to the same array as globalarray

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

1

Простой способ клонирования массива - это просто

let localarray = globalarray.slice();

Я делаю это по-другому для глубокого клонирования:

clone: function() {
    var clone = undefined;
    var instance = this;

    if ( XScript.is.xobject(instance) ) {
        clone = {};
        for ( var prop in instance ) {
            if ( instance.hasOwnProperty(prop) ) {
                var p = instance[prop];
                if ( XScript.is.xobject(p) ) p = p.clone();
                clone[prop] = p;
            }//END IF this
        }//END FOR prop

        return clone;
    }//END IF xobject

    if ( XScript.is.xarray(instance) ) {
        clone = instance.slice(0);
        return clone;
    }

    return clone;
}//END FUNCTION clone

Этот клон потребует, чтобы вы прикрепляли объект клона к прототипу объекта и проверяли, есть ли его массив, объект или другое. Я не изменяю функцию, чтобы соответствовать всем вашим потребностям, потому что нужно немного научиться ее менять и что делать, а не копировать макароны. Плюс это просто пример.

1

В JavaScript (как и во многих других языках) объекты передаются по ссылке. Массивы также передаются по ссылке (потому что массив фактически является типом объекта). Поэтому, когда вы говорите: let localarrray = globalarray, вы на самом деле устанавливаете localarray указателю, который разрешает globalarray.

Существует несколько стратегий получения подлинной копии. Если вы пытаетесь получить новую копию исходного массива, функция прототипа массива .map() является одним из наиболее целенаправленных инструментов для задания. Это будет выглядеть так:

let localarray = globalarray.map(element => element);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню