简体   繁体   中英

Count number of elements in TypedArray in JavaScript

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM