Путаница над javascript .map () может изменить исходный массив вместо назначения преобразования массива - PullRequest
1 голос
/ 24 января 2020

Итак, я работал над некоторым кодом и заметил, что предыдущий человек изменял исходный массив по ссылке, и я думал, что функция .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;
}

при передаче массива orders выглядит так:

enter image description here

и, пройдя через функцию, выглядит так:

enter image description here

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

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

1 Ответ

4 голосов
/ 24 января 2020

Методы функционального массива в 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(), и его можно использовать в качестве замены в приведенном выше примере.

...