8

can someone please explain me how does this line of code work.

[].push.apply(perms, permutation(arr.slice(0), start + 1, last));

This function generates an array of all permutations of an input array;

var permutation = function(arr, start, last){
  var length = arr.length;

  if(!start){
    start = 0;
  }

  if(!last){
    last = length - 1;
  }

  if( last === start){
    return [arr];
  }

  var temp;
  var perms = [];

  for(var i = start; i < length; i++){
    swapIndex(arr, i, start);
    console.log(arr);

    [].push.apply(perms, permutation(arr.slice(0), start + 1, last)); 

    swapIndex(arr, i, start);
  }

  return perms;
};
Andrew Marshall
  • 89,426
  • 20
  • 208
  • 208
Davis Davis
  • 429
  • 4
  • 12
  • Are you interested in `apply` method ? This is one of the type you can call Javascript methods/function. You can read about `call` and `apply`. Probably https://stackoverflow.com/questions/1986896/what-is-the-difference-between-call-and-apply can help – murli2308 Jul 18 '17 at 13:04
  • 1
    What specifically is causing the confusion? – Dave Newton Jul 18 '17 at 13:13

2 Answers2

6

[].push creates a new array, then fetches push which is the same as Array.prototype.push but with creating an unused object each time that needs to be garbage collected.

If you call Array.prototype.push(5) it wont work since this wouldn't be set to an array or something that extends an array. Thus you need to use either Function.call, Function.apply or Function.bind to set this if you want to use an arbitrary function to work as a method.

If you have Array.prototype.push.apply(thisObject, arrArguments) is the same as thisObject.push(arrArguments[0], arrArguments[1], ..., arrArguments[n]) if thisObject has push in its prototype chain. Since perms is an array and has push in it's own prototype chain it could be replaced with:

perms.push.apply(perms, permutation(arr.slice(0), start + 1, last));

The use of apply is because push gets all the contents of the permutations array as arguments. thus if permutations(....) returned [1,2,3] it would be synonymous with perms.push(1, 2, 3). You could write it without apply by calling push for each element:

for (var e of permutation(arr.slice(0), start + 1, last)) {
    perms.push(e);
}

And in ES6 you can simply use the spread syntax which is the same as apply but simpler to comprehend:

perms.push(...permutation(arr.slice(0), start + 1, last))
Sylwester
  • 44,544
  • 4
  • 42
  • 70
1

Expanded it is the same as:

Array.prototype.push.apply(arrryToPushTo, ArrayOfItemsToPush)

apply() is from Function.prototype.apply() and Array.prototype.push is a function.

Using an empty array instead of writing "Array.prototype" exposes the push() method that apply() can be called on and is done simply because "[]" is less characters to write than "Array.prototype".

charlietfl
  • 164,229
  • 13
  • 110
  • 143