В компьютерном программировании побитовые операторы (&, |, ~) считаются быстрой и недорогой операцией. Соответствуют ли эти преимущества веб-разработчикам и стоят ли они других затрат на использование?

Все программисты используют логические операторы почти в каждой компьютерной программе. Веб-разработчики, использующие JavaScript, также используют логические операторы, но при нажатии клавиши SHIFT, а затем конвейера | или на клавишу «и» &, мы регулярно нажимаем дважды и никогда не используем побитовую версию этих операторов.

В JavaScript очень редко используются побитовые операторы, хотя в языке их довольно много.

Итак, каковы преимущества побитовых операторов? Почему эти операторы вообще существуют в JavaScript?

Биты

Компьютерный язык - это машинный язык, что означает двоичную систему из битов. Побитовые операторы имеют то преимущество, что они выполняют примитивные и более быстрые операции. Быстрее «обычных» логических операторов.

Важно знать, что побитовые операторы имеют еще одно отличие от логических операторов.
Побитовые операторы не возвращают истинное или ложное значение, они возвращают целое число.

Для лучшего понимания системы битов давайте сделаем быстрый обзор:
Когда мы выполняем операцию с побитовой системой, мы должны преобразовать десятичное число из базы 10 в двоичное (база 2):
итак, 1 равно 1 , 2 равно 10, 3 равно 11 и т. Д.

function convertToBinaryWithJS(decimalNumber){
 return (decimalNumber >>> 0).toString(2); // returns binary version of the number (as string)
}

Все побитовые операции JS выполняются с 32-битными двоичными числами и возвращают стандартные числовые значения JS. Например, если мы берем 2 операнда, значение первого операнда 5 (101), а второго операнда 9 (1001), мы должны проверить биты, чтобы узнать результат:

5 & 9 : 0101 & 1001 = 0001 // 1 (return true only the rightmost bit)
5 | 9 : 0101 | 1001 = 1101 // 1 + 4 + 8 = 13 (every bit - the second bit is 0)

Примеры, которые могут быть полезны в рутинном коде использования побитовых операторов:

//  instead using a modulus to check odd and even: 
function oddOrEven(num) { 
  return (num % 2===1) ? "odd" : "even";
}
// bitwise
function oddOrEven(num) {
  return ( num & 1 ) ? "odd" : "even";
}
// instead Math.floor with parseInt
   parseInt(Math.floor("3.5"));
// bitwise
"any privitive" | "3.5"; //returns 3 as number
// hex to RGB
function hexToRgb(hex) {
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : null;
}
// right shift bitwise operator
function hextoRgb(c) {
    c = '0x' + c.substring(1);
    return [(c >> 16) & 255, (c >> 8) & 255, c & 255]; 
}

Примеры побитового использования в реальном мире

В sizzle.js, механизме выбора jQuery, мы можем найти использование встроенного метода объекта документа «compareDocumentPosition ()» (далее «сравнить»), который сравнивает позиции двух элементов DOM и возвращает число, представляющее относительное положение 2 элемента. Это код из библиотеки:

var sortOrder; 
if ( document.documentElement.compareDocumentPosition ) {  
sortOrder = function( a, b ) {    
if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {      if ( a == b ) {        
hasDuplicate = true;      
}      
return a.compareDocumentPosition ? -1 : 1;    }
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;    if ( ret === 0 ) {      
hasDuplicate = true;    
}    
return ret;

Вышеупомянутая функция сортирует элементы страницы в массиве в соответствии с положением элементов. После проверки возможности текущего браузера использовать метод «сравнения» и подтверждения того, что все элементы массива являются элементами DOM, используется побитовый оператор &.

Возможность побитового использования & в этой функции обусловлена ​​тем, что метод DOM «сравнения» возвращает постоянное число для каждого состояния относительного положения между двумя элементы. Необходимость использования заключается в том, что в определенных ситуациях метод «сравнения» складывает две константы вместе.

Когда мы берем элемент ‹span› и помещаем его внутрь элемента ‹p›, «compare» вычисляет относительное положение 4 (после p) и другое относительное положение 16 (внутри p). Таким образом, он вернет число 20.

Библиотека предотвращает это добавление, проверяя третий бит с помощью «& 4» и добиваясь того, что возвращаемое значение будет 4 в случае вложенных элементов.

const p1 = document.getElementById("p1");
const span1 = document.getElementById("span1");
const ret = p1.compareDocumentPosition(span1) ;
document.getElementById("demo").innerHTML = ret & 4; // return 4 instead of 20

Другое аналогичное использование можно найти в методе jQuery event.which, который указывает конкретную клавишу (на клавиатуре) и конкретную кнопку мыши, которая была нажата (левый-1, средний-2 (использованные ролики в прошлом), справа-3).
Его реализация также использует побитовый оператор &:

// Add which for click: 1 == left; 2 == middle; 3 == right
// Note: button is not normalized, so don't use it
if ( !event.which && event.button )
        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : (   event.button & 4 ? 2 : 0 ) ));

В приведенном выше коде мы видим 3 троичных проверки, которые определяют, какая кнопка мыши была нажата.
Опять же, мы можем увидеть некоторое использование в реальном приложении побитового оператора, когда метод возвращает число, а затем мы можем определить, какая кнопка мыши была нажата.

Второстепенные мысли

Исследование этой проблемы выявило множество аргументов в пользу эффективности побитовых операций в JavaScript:

Https://stackoverflow.com/questions/9075351/bitwise-operations-significance-in-javascript

Https://dreaminginjavascript.wordpress.com/2009/02/09/bitwise-byte-foolish/

JS выполняет поразрядные вычисления с 32-битными двоичными числами и преобразует их обратно в 64-битные, в числовое число JS, это означает, что есть другие затраты на работу ЦП.
Кроме того, JS не имеет прямого доступа к оборудованию, как другие языки программирования, поэтому тема производительности здесь не так актуальна.

Резюме

Отложив в сторону проблему производительности, я думаю, что побитовые операторы все еще имеют эти дополнительные минусы:
1. Разработчики могут запутаться при чтении кода.
2. Побитовые операторы всегда возвращают целое число, а как человеческие существа, мы могли бы не ожидать результата и обрабатывать его правильно.

Итак, теперь мы знаем, почему в JS не так широко используются побитовые операторы. На мой взгляд, веб-разработчики должны использовать побитовые операторы только в редких случаях и, что наиболее важно, после рассмотрения параметров вывода для всех случаев (и, конечно же, после добавления некоторых комментариев для других разработчиков…).