Что почему!? Хитрый код JS и [.concat]

Я просто просматривал исходный код Laravel Mix (настройка веб-пакета), чтобы вдохновиться на настройку моего собственного веб-пакета, когда я наткнулся на это.

rules.push(...[].concat(newRules))

Я не могу понять, в чем смысл этого, но я верю, что Тейлор не стал бы включать ничего лишнего просто так.

Наверняка что-то из этого так же хорошо?

rules.concat(newRules)

or

rules.push(...newRules)

или даже старый добрый цикл for! Но зачем объединять пустой массив перед распределением элементов?

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


person sysdevmike    schedule 04.11.2018    source источник
comment
Похоже, они хотят использовать Symbol.isConcatSpreadable поведение, а не только протокол итерации.   -  person Bergi    schedule 04.11.2018
comment
Возможно, rules.push(...Array.from(newRules)) немного понятнее. Или rules = rules.concat(newRules);   -  person Jonas Wilms    schedule 04.11.2018


Ответы (1)


Я могу только предполагать, поскольку я не автор кода, но я предполагаю, что намерение состоит в том, чтобы добавить newRules к rules, где newRules может быть любым типом (а не только массивом). concat создаст новый массив в то время как мы хотим, чтобы исходный массив мутировал. push изменяет массив, но как вы обрабатываете случай, когда newRules является массивом? Вы не можете просто вставить newRules в rules, потому что это будет массив внутри массива, и вы не можете распространять newRules, потому что не все является итерируемым. [].concat(newRules) добавит все newRules в массив, который по существу «преобразует» немассивы в массив, а распространение этого массива внутри push добавит эти элементы в rules.

Ознакомьтесь с тестовыми примерами ниже и нажмите Выполнить фрагмент, чтобы увидеть его в действии:

const PASSED = '✅ PASSED';
const FAILED = '❌ FAILED';

(() => {
  console.log('`rules.concat(newRules)`');
  (() => {
    const expectation = [1, 2, 3, 4, 5, 6];
    const rules = [1, 2, 3];
    const newRules = [4, 5, 6];
    rules.concat(newRules);
    console.log('where `newRules` is an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();

  (() => {
    const expectation = [1, 2, 3, 4];
    const rules = [1, 2, 3];
    const newRules = 4;
    rules.concat(newRules);
    console.log('where `newRules` is not an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();
  console.log('');
})();

(() => {
  console.log('');
  console.log('`rules.push(newRules)`');
  (() => {
    const expectation = [1, 2, 3, 4, 5, 6];
    const rules = [1, 2, 3];
    const newRules = [4, 5, 6];
    rules.push(newRules);
    console.log('where `newRules` is an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();

  (() => {
    const expectation = [1, 2, 3, 4];
    const rules = [1, 2, 3];
    const newRules = 4;
    rules.push(newRules);
    console.log('where `newRules` is not an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();
  console.log('');
})();

(() => {
  console.log('');
  console.log('`rules.push(...[].concat(newRules))`');
  (() => {
    const expectation = [1, 2, 3, 4, 5, 6];
    const rules = [1, 2, 3];
    const newRules = [4, 5, 6];
    rules.push(...[].concat(newRules));
    console.log('where `newRules` is an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();

  (() => {
    const expectation = [1, 2, 3, 4];
    const rules = [1, 2, 3];
    const newRules = 4;
    rules.push(...[].concat(newRules));
    console.log('where `newRules` is not an array:', _.isEqual(expectation, rules) ? PASSED : FAILED);
  })();
})();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

person Wing    schedule 04.11.2018
comment
Вот и все!! Большое спасибо за разбор и за подробный пример. Я до сих пор не понимаю, как [].concat(newRules) преобразует newRules в массив (поскольку concat работает и с простыми одиночными элементами), но имеет смысл изменить исходный массив и по-прежнему иметь возможность принимать массив! - person sysdevmike; 09.11.2018
comment
Если вы объедините два массива, вы получите один массив с двумя объединенными массивами. Если вы объедините не-массив с массивом, вы получите один массив с не-массивом, добавленным в конец. Посмотрите на эти два примера, которые оба производят [1, 2, 3]: [1, 2].concat(3) и [1, 2].concat([3]). - person Wing; 12.11.2018