Некоторые подробности об операторе беззнакового сдвига вправо в JavaScript «›››» с другой информацией об операторе сдвига битов сверху.

Немного ‹‹ и ›› перед

Прежде чем мы обсудим «›››», нам нужно небольшое введение для операторов ‹‹ (сдвиг влево) и ›› (сдвиг вправо).

Они сдвигают биты левого операнда на количество позиций, указанное в правом операнде, в направлении стрелок.

Пример: 0010 << 1 приведет к 0100, а 0100 >> 1 будет 0010.

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

>>>

››› называется «оператор сдвига вправо без знака» или «оператор сдвига вправо с нулевым заполнением».

Если вы сделаете x >>> y, он сдвинется на y битов вправо и заполнит 0 слева. Биты, выталкиваемые справа, отбрасываются. И не сохраняет знак после сдвига.

>> vs >>>

Отрицательный знак (-) представлен установкой самого левого бита как 1. Когда >> используется для отрицательного числа, результат снова получит 1 как самый левый бит, чтобы сохранить знак. Но >>> подталкивает 0 слева даже к отрицательным числам без сохранения бита знака. Таким образом, результат всегда будет положительным числом.

Когда вы наблюдаете следующее, вы увидите, что >> всегда сохраняет 1 в качестве левого бита, если 1 была раньше.

10000000000000000000000000000010 >> 1; 
// 11000000000000000000000000000001
10000000000000000000000000000010 >>> 1; 
// 01000000000000000000000000000001

10000000000000000000000000000100 >> 2; 
// 11100000000000000000000000000001
10000000000000000000000000000100 >>> 2; 
// 00100000000000000000000000000001

10000000000000000000000000100000 >> 4; 
// 11111000000000000000000000000010
10000000000000000000000000100000 >>> 4; 
// 00001000000000000000000000000010

>>> 0

Давайте попробуем не выполнять сдвиг с помощью операторов сдвига.

1 >> 0; // 1      Ok
-1 >> 0; // -1    Looks good
1 >>> 0; // 1     Makes sense
-1 >>> 0; // 4294967295  I'm JavaScript

Чего ждать?

Как получается, что если я сдвину нулевые биты, я получу большое число?

Чтобы понять это, давайте воспользуемся toString(2), чтобы увидеть результаты в двоичном виде.

(1 >> 0).toString(2); // 1
(-1 >> 0).toString(2); // -1
(1 >>> 0).toString(2); // 1
(-1 >>> 0).toString(2); // 11111111111111111111111111111111  (4294967295 in decimal)

Отрицательные числа обычно представляются с дополнением до 2.

2's complement = reverse the bits and add 1
-1 = 2's complement of 1
1 in 32-bit binary // 00000000000000000000000000000001
1's complement of 1 = flip all bits // 11111111111111111111111111111110
2's complement of 1 = 1's complement + 1 // 11111111111111111111111111111110 + 1
-1 // 11111111111111111111111111111111

Итак, что случилось,

  • -1 преобразуется в дополнение до 2.
  • Сдвиг на нулевое количество битов вправо. Это означает, что не сдвигайте биты.
  • Возвращает результат как 32-разрядное целое число без знака.

Это всегда приводит к целому числу без знака между 0 (все 0 бит) и 0xFFFFFFFF (все 1 бит), потому что после операции >>> единицы слева больше не представляют число со знаком.

Так это все?

Нет, это не так. Мы говорим о JavaScript.

Когда жизнь дает лимоны, JavaScript пытается сделать из них апельсиновый сок.

-1 >>> 0; // 4294967295  Ok, I get it
// But,
"lemons" >> 0; // 0     🤷‍♂️
"lemons" >>> 0; // 0     🤷‍♂️
undefined >> 0; // 0     🤷‍♂️
undefined >>> 0; // 0     🤷‍♂️
null >> 0; // 0     🤷‍♂️
null >>> 0; // 0     🤷‍♂️

Это боги принуждения JavaScript творят свое волшебство.

Когда >>> не удалось привести «лимоны» к числу, это привело к 0, чтобы гарантировать целочисленный результат.

Пример использования

let numbers = [1, 2, 3, 4, 5];
numbers.splice(numbers.indexOf(6), 1);
// numbers -> [1,2,3,4] --- Oops

Всякий раз, когда вы используете splice с indexOf() в JS, всегда проверяйте, равен ли индекс › 0. В противном случае, если элемент не найден, .splice(-1, 1) удаляет последний элемент.

'420-байтовая альтернатива популярной библиотеке':

numbers.splice(numbers.indexOf(element) >>> 0, 1);

Если indexOf(element) равно -1, мы знаем, что -1 >>> 0 будет 4294967295. Таким образом, сплайсинг не удалит ничего неправильного.

Серьезно, не пишите такой код. Если, конечно, вы не пытаетесь спасти мир, используя на 50 байт меньше!

Что тогда делает ‹‹‹?

Его не существует.

Аккуратно используйте вновь обретенные >>> способности. Лучший способ использования — избегать его.

использованная литература

"Переполнение стека"

МДН

ИзучениеJS