扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
|= 是JavaScript中按位“或”赋值运算符
成都创新互联公司自2013年起,是专业互联网技术服务公司,拥有项目成都做网站、成都网站制作网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元阿克陶做网站,已为上家服务,为阿克陶各地企业和个人服务,联系电话:028-86922220
JavaScript中按位“或”赋值运算符是对变量值与表达式值执行按位“或”,并将结果赋给该变量。使用方法:
result |= expression
其中result是任何变量。
expression是任何表达式。
JavaScript中按位“或”赋值运算符,使用该运算符和使用下面的语句是等效的:
result = result | expression
|= 运算符查看 result 和 expression 的二进制表示法的值,并执行按位“或”操作。该操作的结果如下所示:
0101 (result)
1100 (expression)
----
1101 (输出)
任何时候,只要两个表达式中的其中一个的某位是 1,则结果的该位是 1。否则,结果的该位是 0。
在了解位运算之前, 必须先了解一下什么是原码, 反码和补码, 以及二进制与十进制的转换.
原码
一个数在计算机中是以二进制的形式存在的, 其中第一位存放符号, 正数为0, 负数为1. 原码就是用第一位存放符号的二进制数值. 例如2的原码为00000010, -2的原码为10000010
反码
正数的反码是它本身, 负数的反码是在其原码的基础上, 符号位不变, 其余各位取反.
可见如果一个反码表示的是负数, 并不能直观的看出它的数值, 通常要将其转换成原码再计算
补码
正数的补码是它本身, 负数的补码是在其原码基础上, 符号位不变, 其余各位取反, 最后+1. (即负数的补码为在其反码的基础上+1)
可见对于负数, 补码的表示方式也是让人无法直观的看出其数值的, 通常也需要转换成原码再计算.
正整数十进制转二进制
正整数的十进制转二进制的方法为将一个十进制数除以2, 得到的商再除以2, 以此类推知道商为1或0时为止, 倒序取得除得的余数, 即为转换所得的二进制数.
负整数十进制转二进制
负整数的十进制转二进制, 先将该负整数对应的正整数转为二进制, 然后对其取反再+1. 即补码的形式
十进制小数转二进制
十进制小数转二进制的方法为"乘2取整", 对十进制的小数部分乘2, 得到的整数部分即是相应的二进制码数, 然后继续对得到的小数部分乘2, 如此不断重复, 直到小数部分为0或达到精度要求为止. 顺序取得每次的整数部分, 即是该十进制小数的二进制表示.
按位运算符有6个
: 按位与
|: 按位或
^: 按位异或
~: 按位取反
: 右移
: 左移
将运算数以二进制表示, 对应位都为1, 则结果为1, 否则为0.
使用场景示例:
判断一个数是奇数还是偶数
奇数的二进制码的最后一位数肯定是1, 而1只有最后一位为1, 按位与运算后, 结果肯定只有最后一位数是1. 而偶数的二进制表示的最后一位数是0, 和1进行按位与运算, 结果的所有位都是0.
将运算数以二进制表示, 对应位有一个为1, 则结果为1, 否则为0.
使用场景示例:
对浮点数向下求整
其实浮点数是不支持位运算的, 所以会先把小数位丢弃, 然后以整数进行位运算, 而任何数与0进行按位或操作, 结果都是它本身, 就好像是对浮点数向下求整.
将运算数以二进制表示, 对应位相同为0, 相异为1.
异或满足交换律和结合律, 数字与它本身进行异或操作, 得到0; 数字与0进行异或操作, 得到它本身.
使用场景示例:
交换两个变量数字的值
将操作数转换为二进制数, 然后按位求反.
浮点数是不支持位运算的,所以会先直接去除小数部分,转成整数再进行位运算,就好像是对浮点数向下求整.
~~可以进行类型转换,位运算会默认将非数字类型转换成数字类型再进行运算 (转换结果为整数 直接去除小数部分)
使用场景示例:
类型转换
移位运算符将操作数转换成二进制, 然后向左或向右移动, 超过的位丢弃, 空出的位补0.
使用场景示例:
类型转换
任何小数 把它 0可以取整
如3.14159 0 = 3;
其默认将非数字类型的转换为数字类型再做运算的性质与 ~~ , | 0 一样
| 是或运算符
或运算的基本原理是:两个数相对应的位都为1或其中一个为1则结果为1,如果都是0则结果为0。
比如:
4 的各位为 0100
8 的各位为 1000
那么 4|8 就是 1100
转换为10进制就是12
通俗点来理解,或运算可以使两种状态进行叠加,比如
0100 代表勇敢
1000 代表机智
那么经过或运算的结果1100就代表既勇敢又机智
如果1100再和0100进行或运算,结果仍然是1100,因为1100已经包含0100这个状态了
不知你听明白了没有?
按位操作符(Bitwise operators)会使用内置函数, 7.1.5 ToInt32 ( argument ) ,
先将其操作数转换成32位有符号整数 ,再进行位操作,最后返回一个32位有符号整数。
包括,
12.5.8 Bitwise NOT Operator ( ~ ) ,
12.9.3 The Left Shift Operator ( ) ,
12.9.4 The Signed Right Shift Operator ( ) ,
12.12 Binary Bitwise Operators
因此, a | 0 , 0 | a ,都可以将变量 a 中数值转换为32位有符号整数。
某些特殊的值,并不是32位有符号整数的安全范围,它们会被转换为 0 。
在计算机中表示有符号整数,通常使用 补码 (two's-complement)进行编码。
它将字的最高有效位解释为符号位,符号位被置为 1 时,表示值为负,
符号位被置为 0 时,表示值为非负。
因此,字长为4的二进制数 0001 表示整数 1 ,其中 0*2^3+0*2^2+0*2^1+1*2^0=1 ,
而 1111 就表示整数 -1 ,其中 -1*2^3+1*2^2+1*2^1+1*2^0=-1 。
负数的补码,还可以按照“ 逐位取反后,加一 ”的方式来获取相应的整数值。
例如, 1111 逐位取反 0000 ,然后再加一 0001 ,它是 1 的二进制表示,
因此 1111 就是表示 -1 了。
~ 操作符,它首先将操作数转换成32位有符号整数,然后再按位取反。
例如, 1 的32位补码编码为,
按位取反,
它表示什么呢?
先看最高为的符号位,是 1 ,它表示一个负数,
然后“逐位取反后,加一”, 00000000 00000000 00000000 00000002 值为 2 ,
因此, 11111111 11111111 11111111 11111110 表示 -2 。
一般的, 可以证明 ,
对于任意的32位有符号整数 x 来说, ~x === -(x+1) 。
详细证明见文后的附录。
ECMAScript中,数组元素的索引范围是, 0 到 Math.pow(2,32)-2 。
规范 9.4.2 Array Exotic Objects 中指出,
超过数组 length 的索引,会被看做数组的属性值,
因此, indexOf 返回的最大值为 Math.pow(2,32)-2 。
Array.prototype.indexOf ,
会返回给定数组元素在数组中的索引,如果找不到给定元素,就返回 -1 。
因为只有 ~-1 等于 0 ,其他索引值取反都非 0 ,
所以,人们经常使用 !~a.indexOf(element) 来判断元素是否在数组中。
这里有一个值得注意的事情,由于 ~ 会首先将操作数转换成32位有符号整数,
所以, -1 和 Math.pow(2,32)-1 具有相同的编码,
但是,数组的最大索引为 Math.pow(2,32)-2 ,小于上面这个值,
因此,对 indexOf 返回的值进行取反,除了 -1 之外,总是非 0 值,是安全的做法。
下面给出 ~x === -(x+1) 的证明。
(1)先看正整数
对于32位正整数来说,它的二进制编码为,
其中 n 表示 0 或者 1 ,
则, ~x 为,
其中 u 为 n 的取反结果。
以上二进制表示,如果看成32位有符号整数,则由于符号位 1 ,它是一个负数,
其绝对值为,“逐位取反后,加一”,即为, (0nnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn)+1 === x+1 ,
即, -(x+1) 。
因此,对于正数, ~x === -(x+1) 。
(2)再看负整数
对于32位负整数来说,它的二进制编码为,
其中 n 表示 0 或者 1 ,
则, ~x 为,
其中 u 为 n 的取反结果。
设 0uuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu 的值为 t ,
则 1nnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn 的值为, -(t+1) ,(逐位取反后,加一)。
因此, x === -(t+1) , ~x === t ,
即, ~x === t === -(-(t+1) + 1) === -(x+1) 。
证毕。
你不知道的JavaScript(中卷)
ECMAScript Language Specification
深入理解计算机系统
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流