我正在查看来自 Mozilla 的代码,该代码将过滤器方法添加到 Array,它有一行代码让我感到困惑。
var len = this.length >>> 0;
我以前从未见过在 JavaScript 中使用 >>>。
它是什么,它有什么作用?
我正在查看来自 Mozilla 的代码,该代码将过滤器方法添加到 Array,它有一行代码让我感到困惑。
var len = this.length >>> 0;
我以前从未见过在 JavaScript 中使用 >>>。
它是什么,它有什么作用?
它不仅将非数字转换为数字,还将它们转换为可以表示为 32 位无符号整数的数字。
虽然JavaScript的数字是双精度浮点(*),位运算符(<<
,>>
,&
,|
和~
)在对32位整数运算的定义。执行按位运算会将数字转换为 32 位有符号整数,丢失任何分数和高于 32 的位,然后再进行计算然后转换回数字。
因此,执行没有实际效果的按位运算(例如右移 0 bits >>0
)是一种快速舍入数字并确保其在 32 位 int 范围内的方法。此外,三元>>>
运算符在执行其无符号运算后,将其计算结果转换为 Number 作为无符号整数,而不是其他运算符所做的有符号整数,因此它可用于将负数转换为 32 位二进制补码版本作为一个大数字。使用>>>0
确保您有一个介于 0 和 0xFFFFFFFF 之间的整数。
在这种情况下,这很有用,因为 ECMAScript 根据 32 位无符号整数定义数组索引。因此,如果您试图以array.filter
完全复制 ECMAScript 第五版标准所说的方式实现,您可以像这样将数字转换为 32 位 unsigned int。
(实际上几乎没有实际需要,因为希望人们不会设置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的所有array extra方法实现中都使用了无符号右移运算符,以确保该length
属性是一个无符号的 32 位整数。
length
数组对象的属性在规范中描述为:
每个 Array 对象都有一个 length 属性,其值始终是一个小于 2 32的非负整数。
此运算符是实现它的最短方法,内部数组方法使用该ToUint32
操作,但该方法不可访问且存在于规范中以用于实现目的。
Mozilla数组 extras实现尝试与ECMAScript 5兼容,请查看该Array.prototype.indexOf
方法的描述(第 15.4.4.14 节):
1.让O为调用ToObject传递this值的结果 作为论据。 2.令lenValue为调用O的[[Get]]内部方法的结果 参数“长度”。 3. 令 len 为ToUint32(lenValue)。 ....
如您所见,他们只是想ToUint32
在 ES3 实现上重现该方法的行为以符合 ES5 规范,而且正如我之前所说,无符号右移运算符是最简单的方法。
Driis已经充分解释了操作符是什么以及它做什么。这是它背后的含义/为什么使用它:
将任何方向移动 by0
确实会返回原始数字并将转换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
。尽管如此,我认为这个例子是一个令人讨厌的 hack,原因有两个:
<<<
使用负数时的行为,在上面的示例中可能不打算(或可能发生)副作用。
代码的意图并不明显,正如这个问题的存在所验证的那样。
除非性能绝对至关重要,否则最佳实践可能是使用更具可读性的内容:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)