What is this asm style “x | 0” some javascript programmers are now using?

那年仲夏 提交于 2019-11-27 20:14:17

According to JavaScript Performance for Madmen

Wrapping integer arithmetic expressions in ( ) | 0 allows the runtime to be sure that you're doing integer arithmetic instead of floating-point arithmetic. This allows it to avoid checking for overflow and produce faster code in many cases.

and according to the page, it's true for "most" Javascript runtimes, but doesn't say which.

As a second source, Writing Fast JavaScript For Games & Interactive Applications states

To tell JavaScript engine we want to store integer values [...] we could use bitwise or operator:

and a third source from Microsoft's Writing efficient JavaScript page:

[...] explicitly tell the JavaScript runtime to use integer arithmetic [...] use the bitwise or operator

Also, apart from in comments, none of the pages above mention asm.js, so I suspect such optimizations apply in code not explicitly marked as asm/in browsers that don't explicitly recognize it.

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.

What it actually does can be seen in this fiddle

It's probing the variable against integer type in this case and either "flooring" or set it to 0 if not an integer.

Thus, there's a tremendous differnece to a = a || 0 which would leave a value of 3.2 untouched.

| operator is bitwise OR. It's used to do a bit by bit OR operation on two integers.

The usage here is a shortcut very similar to logical OR || operator to provide default value, with the exception that the result is integer only (as opposed to string...etc)

address = address | 0;

means "if address is a number, let's use it; otherwise, set it to 0".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!