我正在查看Mozilla的代码,它为Array添加了一个过滤方法,它有一行代码使我感到困惑。
var len = this.length >>> 0;
我从未见过>>>之前在JavaScript中使用过。
它是什么,它做了什么?
答案 0 :(得分:189)
它不只是将非Numbers转换为Number,而是将它们转换为可以表示为32位无符号整数的Numbers。
虽然JavaScript的Numbers是双精度浮点数(*),但是按位运算符(<<
,>>
,&
,|
和~
)是根据32位整数的运算来定义。执行按位操作会将数字转换为32位有符号整数,丢失任何分数和高于32的位数,然后再进行计算,然后再转换回数字。
这样做一个没有实际效果的按位运算,比如向右移0位>>0
,是一种快速的方法来舍入数字并确保它在32位的int范围内。此外,三重>>>
运算符在执行无符号运算后,将其计算结果转换为无符号整数而不是其他符号整数,因此可将其用于将负数转换为32- bit-two-complement版本作为一个大数字。使用>>>0
可确保您获得0到0xFFFFFFFF之间的整数。
在这种情况下,这很有用,因为ECMAScript根据32位无符号整数定义了数组索引。因此,如果您尝试以与ECMAScript第五版标准完全相同的方式实现array.filter
,则可以将数字转换为32位无符号整数。
(实际上对此几乎没有实际需要,因为希望人们不会将array.length
设置为0.5
,-1
,1e21
或{{1}但是这是我们正在讨论的JavaScript作者,所以你永远不会知道......)
要点:
'LEMONS'
(*:好吧,它们的定义就像浮动一样。出于性能原因,如果某些JavaScript引擎实际上可以使用它,我不会感到惊讶。但这将是一个你不会得到的实现细节利用任何优势。)
答案 1 :(得分:56)
无符号右移运算符用于Mozilla的所有数组extra 方法实现,以确保length
属性是无符号32位整数
规范中数组对象的length
属性为described:
每个Array对象都有一个length属性,其值始终是小于2 32 的非负整数。
此运算符是实现它的最短方法,内部数组方法使用ToUint32
操作,但该方法无法访问并存在于规范中以用于实现目的。
Mozilla 数组extras 实现尝试ECMAScript 5兼容,请查看Array.prototype.indexOf
方法的说明(第15.4.4.14节):
1. Let O be the result of calling ToObject passing the this value as the argument. 2. Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length". 3. Let len be ToUint32(lenValue). ....
正如您所看到的,他们只是想重现ToUint32
方法的行为以符合ES3实现的ES5规范,正如我之前所说,unsigned right shift operator是最简单的方法
答案 2 :(得分:30)
这是unsigned right bit shift运算符。这与signed right bit shift operator之间的区别在于无符号右移位运算符(&gt;&gt;&gt; )从左边填充零,并且签名右移位运算符(&gt;&gt; )填充符号位,从而在移位时保留数值的符号。
答案 3 :(得分:28)
Driis已经充分解释了运营商是什么以及它做了什么。这是它背后的意义/使用它的原因:
通过0
移动任何方向都会返回原始数字,并将null
投射到0
。您正在查看的示例代码似乎正在使用this.length >>> 0
来确保len
即使未定义this.length
也是数字。
对于很多人来说,按位操作还不清楚(Douglas Crockford / jslint建议不要使用这些东西)。这并不意味着它做错了,但是存在更有利和熟悉的方法来使代码更具可读性。确保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;
答案 4 :(得分:15)
>>>
是无符号右移操作符(see p. 76 of the JavaScript 1.5 specification),而不是>>
,签名右移操作员。
>>>
更改了移位负数的结果,因为在移位时不会保留符号位。例如,可以从解释者那里理解这种后果:
$ 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
所以这里可能要做的是获取长度,如果长度未定义或不是整数,则为0,如上面的"cabbage"
示例所示。我认为在这种情况下可以安全地假设this.length
永远不会是< 0
。不过,我认为这个例子是一个讨厌的黑客,原因有两个:
使用负数时<<<
的行为,在上面的示例中可能没有(或可能发生)副作用。
代码的意图不明显,因为此问题的存在会验证。
最佳做法可能是使用更具可读性的东西,除非性能绝对至关重要:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
答案 5 :(得分:10)
有两个原因:
&gt;&gt;&gt;的结果是一个“积分”
undefined&gt;&gt;&gt; 0 = 0(因为JS会尝试将LFS强制转换为数字上下文,这也适用于“foo”&gt;&gt;&gt; 0等等)
请记住,JS中的数字具有double的内部表示。 它只是一种基本输入理智的“快速”方式。
然而, - 1&gt;&gt;&gt; 0(哎呀,可能不是所需的长度!)
答案 6 :(得分:0)
下面的示例Java代码很好地解释了:
int x = 64;
System.out.println("x >>> 3 = " + (x >>> 3));
System.out.println("x >> 3 = " + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));
输出如下:
x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000