From 310fd066e91f454b990372ffa30e803cc8120975 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:56:40 +0100 Subject: unslug zh-cn: move --- .../operators/bitwise_operators/index.html | 756 --------------------- 1 file changed, 756 deletions(-) delete mode 100644 files/zh-cn/web/javascript/reference/operators/bitwise_operators/index.html (limited to 'files/zh-cn/web/javascript/reference/operators/bitwise_operators') diff --git a/files/zh-cn/web/javascript/reference/operators/bitwise_operators/index.html b/files/zh-cn/web/javascript/reference/operators/bitwise_operators/index.html deleted file mode 100644 index 4bdd7a1bc7..0000000000 --- a/files/zh-cn/web/javascript/reference/operators/bitwise_operators/index.html +++ /dev/null @@ -1,756 +0,0 @@ ---- -title: 按位操作符 -slug: Web/JavaScript/Reference/Operators/Bitwise_Operators -tags: - - js ^ & Bitwise Operators -translation_of: Web/JavaScript/Reference/Operators -translation_of_original: Web/JavaScript/Reference/Operators/Bitwise_Operators ---- -
{{jsSidebar("Operators")}}
- -

概述

- -

按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值。例如,十进制数9,用二进制表示则为1001。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。

- -

下面的表格总结了JavaScript中的按位操作符:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
运算符用法描述
按位与( AND)a & b对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
按位或(OR)a | b对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
按位异或(XOR)a ^ b对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
按位非(NOT)~ a反转操作数的比特位,即0变成1,1变成0。
左移(Left shift)a << b将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
有符号右移a >> b将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。
无符号右移a >>> b将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。
- -

有符号32位整数

- -

所有的按位操作符的操作数都会被转成补码(two's complement)形式的有符号32位整数。补码形式是指一个数的负对应值(negative counterpart)(如 5和-5)为数值的所有比特位反转后,再加1。反转比特位即该数值进行’非‘位运算,也即该数值的反码。例如下面为整数314的二进制编码:

- -
00000000000000000000000100111010
-
- -

下面编码 ~314,即 314 的反码:

- -
11111111111111111111111011000101
-
- -

最后,下面编码 -314,即 314 的反码再加1:

- -
11111111111111111111111011000110
-
- -

补码保证了当一个数是正数时,其最左的比特位是0,当一个数是负数时,其最左的比特位是1。因此,最左边的比特位被称为符号位(sign bit)。

- -

0 是所有比特数字0组成的整数。

- -
0 (base 10) = 00000000000000000000000000000000 (base 2)
-
- -

-1 是所有比特数字1组成的整数。

- -
-1 (base 10) = 11111111111111111111111111111111 (base 2)
-
- -

-2147483648(十六进制形式:-0x80000000)是除了最左边为1外,其他比特位都为0的整数。

- -
-2147483648 (base 10) = 10000000000000000000000000000000 (base 2)
-
- -

2147483647(十六进制形式:0x7fffffff)是除了最左边为0外,其他比特位都为1的整数。

- -
2147483647 (base 10) = 01111111111111111111111111111111 (base 2)
-
- -

数字-21474836482147483647 是32位有符号数字所能表示的最小和最大整数。

- -

按位逻辑操作符

- -

从概念上讲,按位逻辑操作符按遵守下面规则:

- - - -

& (按位与)

- -

对每对比特位执行与(AND)操作。只有 a 和 b 都是 1 时,a AND b 才是 1。与操作的真值表如下:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
aba AND b
000
010
100
111
- -
     9 (base 10) = 00000000000000000000000000001001 (base 2)
-    14 (base 10) = 00000000000000000000000000001110 (base 2)
-                   --------------------------------
-14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
-
- -

将任一数值 x 与 0 执行按位与操作,其结果都为 0。将任一数值 x 与 -1 执行按位与操作,其结果都为 x。

- -

| (按位或)

- -

对每一对比特位执行或(OR)操作。如果 a 或 b 为 1,则 a OR b 结果为 1。或操作的真值表:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
aba OR b
000
011
101
111
- -
     9 (base 10) = 00000000000000000000000000001001 (base 2)
-    14 (base 10) = 00000000000000000000000000001110 (base 2)
-                   --------------------------------
-14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)
-
- -

将任一数值 x 与 0 进行按位或操作,其结果都是 x。将任一数值 x 与 -1 进行按位或操作,其结果都为 -1。

- -

补充一些例子:

- -
1 | 0 ;                       // 1
-
-1.1 | 0 ;                     // 1
-
-'asfdasfda' | 0 ;             // 0
-
-0 | 0 ;                       // 0
-
-(-1) | 0 ;                    // -1
-
-(-1.5646) | 0 ;               // -1
-
-[] | 0 ;                      // 0
-
-({}) | 0 ;                    // 0
-
-"123456" | 0 ;            // 123456
-
-1.23E2 | 0;               // 123
-
-1.23E12 | 0;              // 1639353344
-
--1.23E2 | 0;              // -123
-
--1.23E12 | 0;             // -1639353344
- -

^ (按位异或)

- -

对每一对比特位执行异或(XOR)操作。当 a 和 b 不相同时,a XOR b 的结果为 1。异或操作真值表:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
aba XOR b
000
011
101
110
- -
     9 (base 10) = 00000000000000000000000000001001 (base 2)
-    14 (base 10) = 00000000000000000000000000001110 (base 2)
-                   --------------------------------
-14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)
-
- -

将任一数值 x 与 0 进行异或操作,其结果为 x。将任一数值 x 与 -1 进行异或操作,其结果为 ~x。

- -

~ (按位非)

- -

对每一个比特位执行非(NOT)操作。NOT a 结果为 a 的反转(即反码)。非操作的真值表:

- - - - - - - - - - - - - - - - -
aNOT a
01
10
- -
 9 (base 10) = 00000000000000000000000000001001 (base 2)
-               --------------------------------
-~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
-
- -

对任一数值 x 进行按位非操作的结果为 -(x + 1)。例如,~5 结果为 -6。

- -

与 indexOf 一起使用示例:

- -
var str = 'rawr';
-var searchFor = 'a';
-
-// 这是 if (-1*str.indexOf('a') <= 0) 条件判断的另一种方法
-if (~str.indexOf(searchFor)) {
-  // searchFor 包含在字符串中
-} else {
-  // searchFor 不包含在字符串中
-}
-
-// (~str.indexOf(searchFor))的返回值
-// r == -1
-// a == -2
-// w == -3
-
- -

按位移动操作符

- -

按位移动操作符有两个操作数:第一个是要被移动的数字,而第二个是要移动的长度。移动的方向根据操作符的不同而不同。

- -

按位移动会先将操作数转换为大端字节序顺序(big-endian order)的32位整数,并返回与左操作数相同类型的结果。右操作数应小于 32位,否则只有最低 5 个字节会被使用。

- -
注:Big-Endian:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,
-又称为"高位编址"。
-Big-Endian是最直观的字节序:
-①把内存地址从左到右按照由低到高的顺序写出;
-②把值按照通常的高位到低位的顺序写出;
-③两者对照,一个字节一个字节的填充进去。
- -

<< (左移)

- -

该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。

- -

For example, 9 << 2 yields 36:

- -
     9 (base 10): 00000000000000000000000000001001 (base 2)
-                  --------------------------------
-9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)
-
- -

在数字 x 上左移 y 比特得到 x * 2y.

- -

>> (有符号右移)

- -

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

- -

例如, 9 >> 2 得到 2:

- -
     9 (base 10): 00000000000000000000000000001001 (base 2)
-                  --------------------------------
-9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
-
- -

相比之下, -9 >> 2 得到 -3,因为符号被保留了。

- -
     -9 (base 10): 11111111111111111111111111110111 (base 2)
-                   --------------------------------
--9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)
-
- -

>>> (无符号右移)

- -

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)

- -

对于非负数,有符号右移和无符号右移总是返回相同的结果。例如 9 >>> 29 >> 2 一样返回 2:

- -
      9 (base 10): 00000000000000000000000000001001 (base 2)
-                   --------------------------------
-9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
-
- -

但是对于负数却不尽相同。 -9 >>> 2 产生 1073741821 这和 -9 >> 2 不同:

- -
      -9 (base 10): 11111111111111111111111111110111 (base 2)
-                    --------------------------------
--9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
-
- -

示例

- -

例子:标志位与掩码

- -

位运算经常被用来创建、处理以及读取标志位序列——一种类似二进制的变量。虽然可以使用变量代替标志位序列,但是这样可以节省内存(1/32)。

- -

例如,有 4 个标志位:

- - - -

标志位通过位序列 DCBA 来表示。当一个位被置位 (set) 时,它的值为 1 。当被清除 (clear) 时,它的值为 0 。例如一个变量 flags 的二进制值为 0101:

- -
var flags = 5;   // 二进制 0101
-
- -

这个值表示:

- - - -

因为位运算是 32 位的, 0101 实际上是 00000000000000000000000000000101。因为前面多余的 0 没有任何意义,所以他们可以被忽略。

- -

掩码 (bitmask) 是一个通过与/或来读取标志位的位序列。典型的定义每个标志位的原语掩码如下:

- -
var FLAG_A = 1; // 0001
-var FLAG_B = 2; // 0010
-var FLAG_C = 4; // 0100
-var FLAG_D = 8; // 1000
-
- -

新的掩码可以在以上掩码上使用逻辑运算创建。例如,掩码 1011 可以通过 FLAG_A、FLAG_B 和 FLAG_D 逻辑或得到:

- -
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
-
- -

某个特定的位可以通过与掩码做逻辑与运算得到,通过与掩码的与运算可以去掉无关的位,得到特定的位。例如,掩码 0100 可以用来检查标志位 C 是否被置位:

- -
// 如果我们有 cat
-if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true
-   // do stuff
-}
-
- -

一个有多个位被置位的掩码表达任一/或者的含义。例如,以下两个表达是等价的:

- -
// 如果我们有 bat 或者 cat 至少一个
-// (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true
-if ((flags & FLAG_B) || (flags & FLAG_C)) {
-   // do stuff
-}
-
- -
// 如果我们有 bat 或者 cat 至少一个
-var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110
-if (flags & mask) { // 0101 & 0110 => 0100 => true
-   // do stuff
-}
-
- -

可以通过与掩码做或运算设置标志位,掩码中为 1 的位可以设置对应的位。例如掩码 1100 可用来设置位 C 和 D:

- -
// 我们有 cat 和 duck
-var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100
-flags |= mask;   // 0101 | 1100 => 1101
-
- -

可以通过与掩码做与运算清除标志位,掩码中为 0 的位可以设置对应的位。掩码可以通过对原语掩码做非运算得到。例如,掩码 1010 可以用来清除标志位 A 和 C :

- -
// 我们没有 ant 也没有 cat
-var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010
-flags &= mask;   // 1101 & 1010 => 1000
-
- -

如上的掩码同样可以通过 ~FLAG_A & ~FLAG_C 得到(德摩根定律):

- -
// 我们没有 ant 也没有 cat
-var mask = ~FLAG_A & ~FLAG_C;
-flags &= mask;   // 1101 & 1010 => 1000
-
- -

标志位可以使用异或运算切换。所有值为 1 的位可以切换对应的位。例如,掩码 0110 可以用来切换标志位 B 和 C:

- -
// 如果我们以前没有 bat ,那么我们现在有 bat
-// 但是如果我们已经有了一个,那么现在没有了
-// 对 cat 也是相同的情况
-var mask = FLAG_B | FLAG_C;
-flags = flags ^ mask;   // 1100 ^ 0110 => 1010
-
- -

最后,所有标志位可以通过非运算翻转:

- -
// entering parallel universe...
-flags = ~flags;    // ~1010 => 0101
-
- -

转换片段

- -

将一个二进制数的 String 转换为十进制的 Number:

- -
var sBinString = "1011";
-var nMyNumber = parseInt(sBinString, 2);
-alert(nMyNumber); // 打印 11
-
- -

将一个十进制的 Number 转换为二进制数的 String:

- -
var nMyNumber = 11;
-var sBinString = nMyNumber.toString(2);
-alert(sBinString); // 打印 1011
-
- -

自动化掩码创建

- -

如果你需要从一系列的 Boolean 值创建一个掩码,你可以:

- -
function createMask () {
-  var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length;
-  for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++);
-  return nMask;
-}
-var mask1 = createMask(true, true, false, true); // 11, i.e.: 1011
-var mask2 = createMask(false, false, true); // 4, i.e.: 0100
-var mask3 = createMask(true); // 1, i.e.: 0001
-// etc.
-
-alert(mask1); // 打印 11
-
- -

逆算法:从掩码得到布尔数组

- -

如果你希望从掩码得到得到 Boolean Array

- -
function arrayFromMask (nMask) {
-  // nMask 必须介于 -2147483648 和 2147483647 之间
-  if (nMask > 0x7fffffff || nMask < -0x80000000) {
-    throw new TypeError("arrayFromMask - out of range");
-  }
-  for (var nShifted = nMask, aFromMask = []; nShifted;
-       aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1);
-  return aFromMask;
-}
-
-var array1 = arrayFromMask(11);
-var array2 = arrayFromMask(4);
-var array3 = arrayFromMask(1);
-
-alert("[" + array1.join(", ") + "]");
-// 打印 "[true, true, false, true]", i.e.: 11, i.e.: 1011
-
- -

你可以同时测试以上两个算法……

- -
var nTest = 19; // our custom mask
-var nResult = createMask.apply(this, arrayFromMask(nTest));
-
-alert(nResult); // 19
-
- -

仅仅由于教学目的 (因为有 Number.toString(2) 方法),我们展示如何修改 arrayFromMask 算法通过 Number 返回二进制的 String,而非 Boolean Array:

- -
function createBinaryString (nMask) {
-  // nMask must be between -2147483648 and 2147483647
-  for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
-       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
-  return sMask;
-}
-
-var string1 = createBinaryString(11);
-var string2 = createBinaryString(4);
-var string3 = createBinaryString(1);
-
-alert(string1);
-// 打印 00000000000000000000000000001011, i.e. 11
-
- -

规范

- - - - - - - - - - - - - - - - - - - - - - - - -
SpecificationStatusComment
ECMAScript 1st Edition.StandardInitial definition.
{{SpecName('ES5.1', '#sec-11.4.8', 'Bitwise NOT operator')}}
- {{SpecName('ES5.1', '#sec-11.7', 'Bitwise shift operators')}}
- {{SpecName('ES5.1', '#sec-11.10', 'Binary bitwise operators')}}
{{Spec2('ES5.1')}}
{{SpecName('ES6', '#sec-bitwise-not-operator', 'Bitwise NOT operator')}}
- {{SpecName('ES6', '#sec-bitwise-shift-operators', 'Bitwise shift operators')}}
- {{SpecName('ES6', '#sec-binary-bitwise-operators', 'Binary bitwise operators')}}
{{Spec2('ES6')}}
- -

浏览器兼容性

- -

{{ CompatibilityTable() }}

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Bitwise NOT (~){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise AND (&){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise OR (|){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise XOR (^){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Left shift (<<){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Right shift (>>){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Unsigned right shift (>>>){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureAndroidChrome for AndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Bitwise NOT (~){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise AND (&){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise OR (|){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Bitwise XOR (^){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Left shift (<<){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Right shift (>>){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
Unsigned right shift (>>>){{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}{{ CompatVersionUnknown() }}
-
- -

相关链接

- - -- cgit v1.2.3-54-g00ecf