Каков этот стиль asm "x | 0", который используют некоторые javascript-программисты?
Я видел некоторый критический код javascript с высокой критичностью, например, один из этот проект, который широко использует побитовые операции OR с 0. Пример:
GameBoyAdvanceCPU.prototype.write8 = function (address, data) {
address = address | 0;
data = data | 0;
this.memory.memoryWrite8(address | 0, data | 0);
Я знаю пример использования номеров напольных покрытий с "| 0", но здесь это не так, поскольку они всегда являются int. Это немного похоже на asm.js, так это сказать движку js, что мы работаем с целыми числами, что позволяет некоторые оптимизации? Если да, то какие браузеры сделают эти оптимизации?
Любые указатели на то, как это будет работать, будут рассмотрены.
Ответы
Ответ 1
Согласно Производительность JavaScript для Madmen
Арифметические выражения для целых чисел в ( ) | 0
позволяют времени выполнения убедиться, что вы выполняете целочисленную арифметику вместо арифметики с плавающей запятой. Это позволяет избегать проверки переполнения и более быстрого кода во многих случаях.
и в соответствии со страницей, это верно для "большинства" Javascript runtimes, но не говорит, что.
В качестве второго источника Написание быстрого JavaScript для игр и интерактивных приложений говорится
Чтобы сказать JavaScript-движок, мы хотим хранить целочисленные значения [...], мы могли бы использовать побитовое или операторное:
и третий источник из Написание эффективной страницы JavaScript в Microsoft:
[...] явно указывать время выполнения JavaScript для использования целочисленной арифметики [...] использовать побитовый или оператор
Кроме того, в комментариях ни одна из вышеперечисленных страниц не упоминает asm.js, поэтому я подозреваю, что такие оптимизации применяются в коде, явно не помеченном как asm/в браузерах, которые явно не распознают его.
Ответ 2
Ссылка спецификация Ecmascript 5: 11.10 двоичные побитовые операторы, а именно
Производство A : A @ B
, где @
является одним из побитовых операторов в производные выше (&
; ^
; |
) оцениваются следующим образом:
Пусть lref
- результат оценки A.
Пусть lval
be GetValue(lref)
.
Пусть rref
- результат оценки B.
Пусть rval
be GetValue(rref)
.
Пусть lnum
be ToInt32(lval)
.
Пусть rnum
be ToInt32(rval)
.
Верните результат применения побитового оператора @в lnum
и rnum
. Результатом является подписанное 32-битное целое число.
И отмечая, что ToInt32()
определяется как
Пусть number
является результатом вызова ToNumber
на входном аргументе.
Если число NaN
, +0
, −0
, +∞
или −∞
, верните +0
.
Пусть posInt
be sign(number) * floor(abs(number))
.
Пусть int32bit
be posInt
по модулю 2^32
; то есть конечное целочисленное значение k
типа number
с положительным знаком и меньше чем 2^32
по величине, так что математическая разность posInt
и k
математически является целым числом, кратным 2^32
. < ш > Если int32bit
больше или равно 2^31
, верните int32bit − 2^32
, в противном случае верните int32bit
.
Затем это логически следует (что вы можете подтвердить в своей собственной консоли), например
((Math.pow(2, 32)) + 2) | 0 === 2
(Math.pow(2, 31)) | 0 === -2147483648 === -(Math.pow(2, 31))
И так далее.
Короче говоря, операция превращает число в 32-битное целое число (которое имеет свои навыки, см. второй пример выше и определение ToInt32()
для объяснения), а затем делает логическое или с нулевым, что не измените вывод за пределы первого преобразования.
По сути, это очень рентабельный способ превратить число в 32-разрядное целое, потому что 1) он полагается на встроенный браузер ToInt32()
; и 2) ToInt32(0)
коротких замыканий на 0
(см. выше спецификацию) и, следовательно, практически не добавляет дополнительных накладных расходов.
Ответ 3
Что это на самом деле можно увидеть в этом fiddle
Он исследует переменную типа integer в этом случае и либо "настил", либо устанавливает значение 0, если не целое число.
Таким образом, существует огромное отличие от a = a || 0
, которое оставило бы значение 3.2
нетронутым.
Ответ 4
| оператор побитовое ИЛИ. Он выполнял побитовое ИЛИ операцию на двух целых.
Использование здесь - это ярлык, очень похожий на оператор логический ИЛИ || для предоставления значения по умолчанию, за исключением того, что результат является только целым (в отличие от строки... и т.д.)
address = address | 0;
означает "если адрес - это номер, пусть он его использует, в противном случае установите его на 0".