func.apply(thisValue, [arg1, arg2, ...])Ignoring thisValue, the above invocation is equivalent to:
func(arg1, arg2, ...)So, apply lets us unwrap an array “into” the arguments of a function call. Let’s look at three tricks that apply allows us to perform.
> Math.max.apply(null, [10, -1, 5]) 10
> ["a",,"b"].forEach(function (x) { console.log(x) }) a b > ["a",undefined,"b"].forEach(function (x) { console.log(x) }) a undefined bYou can also check for the presence of holes via the in operator.
> 1 in ["a",,"b"] false > 1 in ["a", undefined, "b"] trueBut if you read a hole, the result is undefined for both holes and undefined elements.
> ["a",,"b"][1] undefined > ["a", undefined, "b"][1] undefined
> Array.apply(null, ["a",,"b"]) [ 'a', undefined, 'b' ]The above works, because apply does not ignore holes, it passes them as undefined arguments to the function:
> function returnArgs() { return [].slice.call(arguments) } > returnArgs.apply(null, ["a",,"b"]) [ 'a', undefined, 'b' ]Alas, you are faced with a quirk here. If Array receives a single numeric argument, an empty array is created whose length is the number [2]:
> Array.apply(null, [ 3 ]) [ , , ]Therefore, if you need this functionality, it is better to write your own function:
function fillHoles(arr) { var result = []; for(var i=0; i < arr.length; i++) { result[i] = arr[i]; } return result; }Example:
> fillHoles(["a",,"b"]) [ 'a', undefined, 'b' ]Underscore gives you the _.compact function which removes all falsy values, including holes:
> _.compact(["a",,"b"]) [ 'a', 'b' ] > _.compact(["a", undefined, "b"]) [ 'a', 'b' ] > _.compact(["a", false, "b"]) [ 'a', 'b' ]
> Array.prototype.concat.apply([], [["a"], ["b"]]) [ 'a', 'b' ]Non-array elements are added as is:
> Array.prototype.concat.apply([], [["a"], "b"]) [ 'a', 'b' ]apply’s thisValue must be [] here, because concat is a method, not a non-method function. Only one level of flattening is performed:
> Array.prototype.concat.apply([], [[["a"]], ["b"]]) [ [ 'a' ], 'b' ]
If you want your code to be self-descriptive, you should consider alternatives, including implementing your own properly named function. Underscore has _.flatten which handles any level of nesting:
> _.flatten([[["a"]], ["b"]]) [ 'a', 'b' ]