我正在查看Mozilla的代码,它为Array添加了一个过滤方法,它有一行代码让我很困惑.
var len = this.length >>> 0;
我以前从未见过用于JavaScript的>>>.
它是什么,它做了什么?
它不只是将非Numbers转换为Number,而是将它们转换为可以表示为32位无符号整数的Numbers.
虽然JavaScript的数字是双精度浮点(*),位运算符(<<
,>>
,&
,|
和~
)在对32位整数运算的定义.在执行计算然后转换回Number之前,执行按位运算会将数字转换为32位signed int,丢失任何分数和高于32的位数.
因此,在没有实际效果的情况下执行按位操作(如向右移位0位>>0
)是一种快速的方法来舍入数字并确保它在32位int范围内.此外,三元>>>
运算符在执行无符号运算后,将其计算结果转换为无符号整数,而不是其他有符号整数,因此可将其用于将负数转换为32位二进制补码版本为大号.使用>>>0
确保您有一个0到0xFFFFFFFF之间的整数.
在这种情况下,这很有用,因为ECMAScript根据32位无符号整数定义了数组索引.因此,如果您尝试以array.filter
完全复制ECMAScript第五版标准所述的方式实现,则可以将数字转换为32位无符号整数.
(在现实中几乎没有实际的需要这是希望的人是不会被设置array.length
到0.5
,-1
,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对象都有一个length属性,其值始终是小于2 32的非负整数.
此运算符是实现它的最短方法,内部数组方法使用该ToUint32
操作,但该方法无法访问并存在于规范中以用于实现目的.
Mozilla 阵列附加实现尝试符合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规范,正如我之前所说,无符号右移运算符是最简单的方法.
那是无符号右移位运算符.这与有符号右移位运算符的区别在于,无符号右移位运算符(>>>)从左边填充零,有符号右移位运算符(>>)用符号位填充,因此移位时保留数值的符号.
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;
>>>
是无符号右移运算符(参见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
因此,这里可能要做的是获取长度,如果长度未定义或不是整数,则为0,如上"cabbage"
例所示.我想在这种情况下可以安全地假设this.length
永远不会< 0
.不过,我认为这个例子是一个讨厌的黑客,原因有两个:
的行为<<<
使用负数时,副作用可能并不旨在(或可能发生)在上面的例子.
代码的意图并不明显,因为这个问题的存在是验证的.
除非性能绝对至关重要,否则最佳做法可能是使用更易读的东西:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
两个原因:
>>>的结果是"积分"
undefined >>> 0 = 0(因为JS会尝试将LFS强制转换为数字上下文,这也适用于"foo">>> 0等)
请记住,JS中的数字具有double的内部表示.它只是一种基本输入理智的"快速"方式.
但是,-1 >>> 0(oops,可能不是所需的长度!)