The code below is modified version of a code taken from the book Professional JavaScript for Web Developers .
// First argument is the type of array that should be returned // Remaining arguments are all the typed arrays that should be concatenated function numElements(typedArrayConstructor, ...typedArrays) { // Count the total elements in all arrays return typedArrays.reduce((x,y) => (x.length || x) + y.length); } console.log(numElements(Int32Array, Int8Array.of(1, 2, 3), Int16Array.of(4, 5, 6), Float32Array.of(7, 8, 9)));
My question is what does the (x.length || x)
do? Why do we need to perform an or
operation on x.length
and x
?
A little more explanation to go with Pointy's answer:
The ||
in JavaScript isn't just a logical OR operation, it deals with "truthy/falsey" values, not just booleans.
undefined
is falsey. When the first operand of ||
is falsey, the second operand is evaluated, and becomes the result of the expression. Thus undefined || 0
undefined || 0
equals 0.
In your sample code, this means when x
is 0, you add 0, and get a proper numeric result. If you try to add to undefined
to another number, all of your calculations turn into NaN
after that.
When .reduce()
is invoked with only one argument, the very first iteration uses element 0 as the first callback parameter and element 1 as the second.
In your case, that means that on the first iteration, x
will be one of the arrays (note that y
is always an array). Thus that little expression differentiates between when it's the first iteration and when it's a subsequent iteration by taking advantage of the fact that
someNumber.length
is always undefined
. (As correctly noted in another answer, it's critical to recall that (undefined || x)
will always be x
, whatever its value may be.) On subsequent iterations therefore x
is the running total of the array lengths.
The .reduce()
could have been written as follows instead:
return typedArrays.reduce((x,y) => x + y.length, 0);
By passing the second argument (0) to .reduce()
, the first callback invocation will be the same as the others, and x
will always be a number.
If x has any elements and x exists then use the length in the sum. Otherwise if length is undefined then return the current element x
Example 1: - happens on first iteration of reduce loop
x is array [1, 2, 3]
x.length || x -> returns the length of array or current total
// summation of code would do the following
firsthArrayLength + secondArrayLength = newTotal
Example 2: - happens on rest of iterations of reduce loop
x is integer 5
x.length || x -> returns x since length of integer is undefined
// summation of code would do the following
currentTotal + curLength = newTotal
NOTE: Keep in mind that with this example if any of the arrays is null or undefined then it will throw since we cannot access property length of undefined or null
So sad that is taken from a book. Using reduce
and ||
like that is reckless and unprofessional -
// First argument is the type of array that should be returned // Remaining arguments are all the typed arrays that should be concatenated const numElements = (constructor, ...arrs) => new constructor(arrs.reduce((r, a) => r + a.length, 0)) const result = numElements ( Int32Array , Int8Array.of(1, 2, 3) , Int16Array.of(4, 5, 6) , Float32Array.of(7, 8, 9) ) console.log(result.constructor) console.log(result) // Int32Array // { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
The description of the function says it should concat the other arrays, not just initialise an empty typed array. Here's what that might look like -
// First argument is the type of array that should be returned // Remaining arguments are all the typed arrays that should be concatenated const concatMixed = (constructor, ...arrs) => { const r = new constructor(arrs.reduce((r, a) => r + a.length, 0)) let i = 0 for (const a of arrs) for (const val of a) r[i++] = val return r } const result = concatMixed ( Int32Array , Int8Array.of(1, 2, 3) , Int16Array.of(4, 5, 6) , Float32Array.of(7.1, 8.2, 9.3) ) console.log(result.constructor) console.log(result) // Int32Array // { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.