Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What, why!? Tricky JS code spread ... and [].concat

Was just going through the source code for Laravel Mix (webpack setup) to get some inspiration on setting up my own webpack when I came across this.

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

I can't figure out what the point of this is but I trust Taylor wouldn't include anything superfluous just for the sake of it.

Surely any of these are just as good?

rules.concat(newRules)

or

rules.push(...newRules)

or even a good old for-loop! But why concat to empty array before spreading the elements?

Much appreciated if anybody can enlighten me on this.

like image 890
sysdevmike Avatar asked Nov 04 '18 12:11

sysdevmike


1 Answers

I can only speculate as I didn't author the code but I imagine the intention is to add newRules to rules where newRules could be any type (not just an array). concat will create a new array while we want the original array mutated. push mutates the array but how do you handle the case where newRules is an array? You can't just push newRules into rules because it'll be an array inside an array and you can't spread newRules because not everything is an iterable. [].concat(newRules) will add all of newRules to an array which essentially 'converts' non-arrays into an array and spreading that array inside push will add those items to rules.

Check out the test cases below and click Run snippet to see it in action:

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>
like image 56
Wing Avatar answered Nov 14 '22 23:11

Wing