Путаница с javascript .map () может изменять исходный массив вместо того, чтобы назначать преобразование массива

Итак, я работал над некоторым кодом и заметил, что предыдущий человек изменял исходный массив по ссылке, и как я думал, что функция .map () в javascript работает, возвращая новую копию с изменениями, возвращаемыми на карте.

В приведенном ниже коде показано, как функция присваивается массиву.

async assignProductCategoriesToOrders(orders) {
    const { selectedOrganisation } = this.props;

    const response = await Fetcher.get(ProductsService
      .ProductCategories.format(selectedOrganisation.id));

    if (!response.ok) {
      orders.map((order) => order.products.map((product) => {
        product.productCategory = { name: 'N/A' };
        return product;
      }));
    } else {
      const productCategories = await response.json();
      orders.map((order) => order.products.map((product) => {
         product.productCategory = productCategories.find((p) => p.id === product.productCategory)
       || { name: 'N/A' };
         return product;
      }));
   }

   return orders;
}

при передаче массива заказов это выглядит так

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

и после выполнения функции это выглядит так

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

Таким образом, он переназначает новый объект productCategory существующему массиву без возврата карт из функции.

Заранее спасибо, было бы здорово узнать, как это работает.


person Chris Marshall    schedule 23.01.2020    source источник
comment
Пожалуйста, публикуйте примеры кода в виде текста, а не скриншотов.   -  person Brian Thompson    schedule 24.01.2020
comment
map действительно возвращает новый массив, но если ваш массив содержит ссылки на вложенные объекты или массивы, они могут быть изменены.   -  person Brian Thompson    schedule 24.01.2020
comment
map возвращает массив, но в функции обратного вызова ясно, что разработчик изменяет существующий объект, а также не сохраняет новый массив карты ни в одной переменной. Разработчик использует карту только для итерации, и это нормально.   -  person Mr_Green    schedule 24.01.2020
comment
Ознакомьтесь с пояснениями в этом ответе, почему вы случайно изменяете вложенные значения.   -  person Brian Thompson    schedule 24.01.2020
comment
Операция должна была использовать forEach   -  person Keith    schedule 24.01.2020


Ответы (1)


Все методы функционального массива в JavaScript (map(), reduce(), filter(), etc) возвращают новые объекты. Ни один из них не работает непосредственно с массивом, для которого вызывается метод.

Однако объекты в JavaScript передаются по ссылке. И map() (и другие методы) создают только мелкую копию массива, к которому они обращаются. Итак, если этот массив состоит из объектов, то копия массива, используемого map(), имеет ссылки на те же самые объекты.

Быстрый пример кода демонстрирует это.

const foo = ['a', 'b'];
foo.map(itm => { 
   itm = 'c';
   return itm;
}
console.dir(foo)   // still ['a', 'b']

const bar = [{id: 'a'}, {id: 'b'}];
bar.map(itm => {
   itm.id = 'c';
   return itm;
}
console.dir(bar)   // the referenced objects were updated [{id: 'c'}, {id: 'c'}]

Во втором примере map() используется для создания побочного эффекта, который обычно противоречит идее функционального программирования. И ваш коллега делает то же самое со своими звонками в orders.map(). Его / ее внутренняя функция преобразовывает свойства отдельных объектов заказов, которые хранятся и на которые ссылается массив клонированных заказов. Использование map() без присвоения его возвращаемого значения - это неприятный запах кода для большинства программистов JavaScript.

Вместо этого в коде следует использовать array.forEach (), который предназначен для устранения побочных эффектов и не имеет возвращаемого значения. Синтаксис forEach() почти идентичен синтаксису map(), и его можно использовать как замену в приведенном выше примере.

person BrianHVB    schedule 23.01.2020