什么是JavaScript >>>操作符,你如何使用它?
我正在从Mozilla的代码中添加一个filter方法到arrays,它有一行代码混淆了我。
var len = this.length >>> 0;
我从来没有见过>>>在JavaScript中使用过。
它是什么,它有什么作用?
它不仅将非数字转换为数字,还将它们转换为可以表示为32位无符号整数的数字。
尽pipeJavaScript的Numbers是双精度浮点数(*),但按位运算符( <<
, >>
, &
, |
和~
)是按照32位整数运算来定义的。 按位操作将数字转换为32位有符号整数,在进行计算之前丢失小于32的任何分数和高位,然后转换回数字。
所以做一个没有实际效果的按位操作,如向右移位0位>>0
,是一个快速的方法来四舍五入一个数字,并确保它在32位int范围内。 此外,三重>>>
运算符在进行无符号运算后,将其计算结果转换为无符号整数的数字,而不是其他人的有符号整数,因此可用于将负数转换为32位数字,作为一个大数字的补码版本。 使用>>>0
确保你有一个0到0xFFFFFFFF的整数。
在这种情况下,这很有用,因为ECMAScript以32位无符号整数定义数组索引。 所以,如果你想以一种与ECMAScript第五版标准所说的完全相同的方式来实现array.filter
,那么你会把这个数字转换为32位的unsigned int。
(事实上,对此没有什么实际需要,希望人们不会将1e21
设置为0.5
, 1e21
或'LEMONS'
。但这是我们正在讨论的JavaScript作者,所以你永远不知道。 ..)
概要:
1>>>0 === 1 -1>>>0 === 0xFFFFFFFF -1>>0 === -1 1.7>>>0 === 1 0x100000002>>>0 === 2 1e21>>>0 === 0xDEA00000 1e21>>0 === -0x21600000 Infinity>>>0 === 0 NaN>>>0 === 0 null>>>0 === 0 '1'>>>0 === 1 'x'>>>0 === 0 Object>>>0 === 0
(*:好吧,它们被定义为像浮动操作一样,如果某些JavaScript引擎实际上使用了整数,出于性能方面的原因,这并不会让我感到惊讶,但这将是一个实现细节,的好处。)
无符号右移运算符用于Mozilla的所有数组extra的方法实现中,以确保length
属性是一个无符号的32位整数 。
数组对象的length
属性在规范中描述如下:
每个Array对象都有一个长度属性,其值始终是一个小于2 32的非负整数。
这个操作符是实现它的最简单的方法,内部的数组方法使用ToUint32
操作,但是这个方法在规范中是不可访问和存在的。
Mozilla 数组extras实现尝试符合ECMAScript 5 ,查看Array.prototype.indexOf
方法的描述(第15.4.4.14节):
设O是调用ToObject传递这个值的结果 作为论据。 2.让lenValue是调用O的[[Get]]内部方法的结果 参数“长度”。 让len成为ToUint32(lenValue) 。 ....
正如你所看到的,他们只是想重现ToUint32
方法的行为,以符合ES3实现中的ES5规范,正如我之前所说的, 无符号右移运算符是最简单的方法。
Driis已经充分解释了运营商是什么,它做了什么。 这是它背后的意义/为什么使用它:
将任何方向移动0
将返回原始数字,并将null
为0
。 看来你正在看的示例代码是使用this.length >>> 0
以确保len
是数字,即使this.length
未定义。
对于很多人来说,按位操作是不清楚的(Douglas Crockford / jslintbuild议不要使用这样的东西)。 这并不意味着它做错了,而是更有利和更熟悉的方法使代码更具可读性。 确保len
为0
更清楚的方法是以下两种方法之一。
// Cast this.length to a number var len = +this.length;
要么
// Cast this.length to a number, or use 0 if this.length is // NaN/undefined (evaluates to false) var len = +this.length || 0;
这是无符号的右移位运算符。 这与有符号位右移位运算符的区别在于, 无符号右位移运算符( >>> )从左侧填充零,而带符号右位移运算符( >> )填充符号位,因此在移位时保留数值的符号。
>>>
是无符号右移运算符 ( 参见JavaScript 1.5规范的第76页 ),而不是符号右移运算符>>
。
>>>
改变负数的移位结果,因为移位时不保留符号位 。 这个后果可以通过一个例子来理解:
$ 1 >> 0 1 $ 0 >> 0 0 $ -1 >> 0 -1 $ 1 >>> 0 1 $ 0 >>> 0 0 $ -1 >>> 0 4294967295 $(-1 >>> 0).toString(16) "ffffffff" $ "cabbage" >>> 0 0
所以这里可能要做的是获得长度,或者如果长度未定义或者不是整数,则按照上面的"cabbage"
示例获得长度。 我认为在这种情况下,假设this.length
将永远不会< 0
。 不过,我认为这个例子是一个讨厌的黑客 ,原因有两个:
-
在使用负数时
<<<
的行为,在上面的例子中可能不会有意(或可能发生)的副作用。 -
代码的意图不明显 ,因为这个问题的存在被证实。
最佳做法可能是使用更可读的东西,除非性能是绝对重要的:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
两个原因:
-
>>>的结果是一个“积分”
-
未定义>>> 0 = 0(因为JS会试图强制LFS到数字上下文,这也适用于“foo”>>> 0等)
请记住,JS中的数字具有double的内部表示。 这只是一个基本的input健全的“快速”方式。
然而 ,-1 >>> 0(哎呀,可能不是所需的长度!)