Referencing the Ecmascript 5 spec: 11.10 Binary Bitwise Operators, namely
The production A : A @ B
, where @
is one of the bitwise operators in
the productions above (&
; ^
; |
), is evaluated as follows:
Let lref
be the result of evaluating A.
Let lval
be GetValue(lref)
.
Let rref
be the result of evaluating B.
Let rval
be GetValue(rref)
.
Let lnum
be ToInt32(lval)
.
Let rnum
be ToInt32(rval)
.
Return the result of applying the bitwise operator@ to lnum
and rnum
. The result is a signed 32 bit integer.
And noting that ToInt32()
is defined as
Let number
be the result of calling ToNumber
on the input argument.
If number is NaN
, +0
, −0
, +∞
, or −∞
, return +0
.
Let posInt
be sign(number) * floor(abs(number))
.
Let int32bit
be posInt
modulo 2^32
; that is, a finite integer value k
of Number
type with positive sign and less than 2^32
in magnitude such that the mathematical difference of posInt
and k
is mathematically an integer multiple of 2^32
.
If int32bit
is greater than or equal to 2^31
, return int32bit − 2^32
, otherwise return int32bit
.
It then logically follows (which you can confirm in your own console) that for example
((Math.pow(2, 32)) + 2) | 0 === 2
(Math.pow(2, 31)) | 0 === -2147483648 === -(Math.pow(2, 31))
And so forth.
Shortly put, the operation turns the number to a 32-bit integer (which has its knacks, see the second example above and the ToInt32()
definition for an explanation) and then does a logical or with zero which doesn't change the output beyond the first conversion.
Essentially it's a very cost-efficient way to turn a number into a 32-bit integer because 1) it relies on browser's built-in ToInt32()
; and 2) ToInt32(0)
short-circuits to 0
(see the spec above) and therefore adds practically no additional overhead.