apply method
apply is a method that all functions have. Its signature is as follows:
func.apply(thisValue, [arg1, arg2, ...])
If the influence of thisValue is not considered, the above call is equivalent to:
func(arg1, arg2, ...)
In other words, apply allows us to "unpack" an array into individual parameters and then pass them on To call a function. Let’s look at three tips in using apply.
Tip 1: Pass an array to a function that does not accept an array as a parameter There is no function in JavaScript that returns the maximum value in an array. However, there is a function Math.max that can return the maximum value among any number of numeric type parameters. Together with apply, we can achieve our goal:
> Math.max.apply(null, [10, -1, 5])
10
Translator’s Note: Note that as long as one value in the parameters of the Math.max method is converted to NaN, the method will directly return NaN
>Math.max(1,null) //Equivalent to Math. max(1,0)
1
>Math.max(1,undefinded) //Equivalent to Math.max(1,NaN)
NaN
>Math.max (0,-0) //Positive zero is larger than negative zero, which is different from ==
0
>Math.max(-0,-1) //Negative zero is larger than -1
- 0
Tip 2: Filling Sparse Arrays Gap in Array
Here is a reminder to readers: In JavaScript, an array is A mapping of numbers to values. So if an element is missing (a gap) at an index and the value of an element is undefined, they are two different situations. The former is detected by the related method in Array.prototype (forEach, map, etc.) when traversing, those missing elements will be skipped, but the latter will not:
> ["a",,"b"].forEach(function (x) { console.log(x) })
a
> ["a",undefined,"b"].forEach(function (x) { console.log(x) })
a
undefined
Translation Author's note: The author here said "an array is a mapping from a number to a value", which is incorrect in a strict sense. The correct statement is "an array is a mapping from a string to a value". Here is the evidence:
>for (i in ["a", "b"]) {
console.log(typeof i) //The index of the array is actually a string
}
"string"
"string"
>["a", "b "].forEach(function (x, i) {
console.log(typeof i) //The i here is not actually an index, it is just an accumulator of numeric type
})
"number"
"number"
You can use the in operator to detect if there are gaps in the array.
> 1 in ["a",,"b"]
false
> 1 in ["a", undefined, " b"]
true
Translator's Note: The reason why 1 can be used here is because the in operator will convert 1 into "1".
You pass you Trying to read the value of this gap will return undefined, which is the same as the actual undefined element.
> ["a",,"b"][1]
undefined
> ["a", undefined, "b"][1]
undefined
Translator's Note: [1] will also be converted into ["1"]
Fill the gap apply with Array( No need to add new here), you can fill the gaps in the array with undefined elements:
> Array.apply(null, ["a",,"b"])
[ 'a', undefined, 'b' ]
This is all because apply will not ignore the gaps in the array and will pass the gaps to the function as undefined parameters:
> function returnArgs() { return [].slice.call(arguments) }
> returnArgs.apply(null, ["a",,"b"])
[ 'a', undefined, 'b' ]
But it should be noted that if the parameter received by the Array method is a single number, this parameter will be regarded as the length of the array and a new Array:
> Array.apply(null, [ 3 ])
[ , , ]
Therefore, the most reliable way is to write a function like this to do this kind of work:
function fillHoles(arr) {
var result = [];
for(var i=0; i < arr.length; i ) {
result[i] = arr[i];
}
return result;
}
Execution:
> fillHoles(["a",,"b"] )
[ 'a', undefined, 'b' ]
The
_.compact function in Underscore will remove all false values in the array, including gaps:
> _.compact(["a",,"b"])
[ 'a', 'b ' ]
> _.compact(["a", undefined, "b"])
[ 'a', 'b' ]
> _.compact(["a", false , "b"])
[ 'a', 'b' ]
Tip 3: Flatten Array Task: Convert an array containing multiple array elements into a first-order array. We use the ability of apply to unpack the array with concat to do this:
> Array.prototype.concat.apply([], [["a"], ["b"]])
[ 'a', 'b' ]
Mixing elements of non-array types is also possible:
> Array.prototype.concat.apply([], [["a"], "b"])
[ 'a', 'b ' ]
ThisValue of the apply method must be specified as [], because concat is an array method, not an independent function. The limitation of this writing method is that it can only flatten second-order arrays at most:
> Array.prototype.concat.apply([] , [[["a"]], ["b"]])
[ [ 'a' ], 'b' ]
So You should consider an alternative . For example, the _.flatten function in Underscore can handle any number of levels of nested arrays:
> _.flatten([[["a"]], ["b"]])
[ 'a', 'b' ]
Reference
JavaScript: sparse arrays vs. dense arrays
ECMAScript.next: Array.from() and Array.of()