我正在查看Mozilla的代码,该代码向Array添加了一个过滤器方法,并且其中的一行代码使我感到困惑。
var len = this.length >>> 0;
我从未见过>>>在JavaScript中使用过。
这是什么,它做什么?
Array.prototype.push
/ Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop(虽然他做了测试,哈哈)。
我正在查看Mozilla的代码,该代码向Array添加了一个过滤器方法,并且其中的一行代码使我感到困惑。
var len = this.length >>> 0;
我从未见过>>>在JavaScript中使用过。
这是什么,它做什么?
Array.prototype.push
/ Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop(虽然他做了测试,哈哈)。
Answers:
它不仅将非数字转换为数字,还将其转换为可以表示为32位无符号整数的数字。
虽然JavaScript的数字是双精度浮点(*),位运算符(<<
,>>
,&
,|
和~
)在对32位整数运算的定义。执行按位运算会将数字转换为32位带符号的int,在进行计算然后再转换回Number之前,它会丢失所有小数和比32高的位。
因此,进行无实际影响的按位运算(例如,向右移位0位>>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
(*:好吧,它们被定义为像float一样。出于性能原因,如果某个JavaScript引擎在可能的时候实际使用了int,这也不会令我感到惊讶。但这将是一个实现细节,您将无需花任何精力。的优势。)
RangeError: invalid array length
。
Array.prototype.filter.call
),因此array
实际上可能不是真实的Array
:它可能是其他一些用户定义的类。(不幸的是,它不能可靠地成为NodeList,这是您真正想要执行的操作,因为它是一个宿主对象。实际上,您唯一可以做的就是使用arguments
伪数组。)
if
当试图确定评估的左侧不是整数时,该语句的外观是什么样的?'lemons'>>>0 === 0 && 0 >>>0 === 0
评估为真?即使柠檬显然是一个词..?
Mozilla 的所有array extra的方法实现中都使用无符号的右移运算符,以确保该length
属性是无符号的32位整数。
length
数组对象的属性在规范中描述为:
每个Array对象都有一个length属性,该属性的值始终是小于2 32的非负整数。
该运算符是实现此操作的最短方法,内部数组方法使用该ToUint32
操作,但是该方法不可访问,并且出于实现目的而存在于规范中。
Mozilla 数组附加实现尝试与ECMAScript 5兼容,请查看Array.prototype.indexOf
方法说明(第15.4.4.14节):
1.令O为调用ToObject传递此值的结果 作为论点。 2.令lenValue为使用调用O的[[Get]]内部方法的结果 参数“长度”。 3.设len为ToUint32(lenValue)。 ....
如您所见,他们只是想重现该ToUint32
方法的行为以使其符合ES3实施中的ES5规范,而且正如我之前所说,无符号右移运算符是最简单的方法。
ToUint32
对我而言似乎有点不必要。
>>>
将其转换为整数,一元制+
则不会。
德里斯已经充分解释了操作员是什么以及它做什么。这是其含义/使用原因:
将方向移动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;
NaN
..例如+{}
...最好将两者结合起来:+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"
上面的示例,此处可能打算获取长度,或者,如果长度未定义或不是整数,则为0 。我认为在这种情况下可以肯定this.length
不会< 0
。尽管如此,我还是认为这个例子很讨厌,原因有二:
的行为<<<
使用负数时,副作用可能不是在上面的例子意图(或可能发生)。
由于存在此问题,因此代码的意图并不明显。
最佳实践可能是使用更具可读性的内容,除非性能绝对关键:
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
-1 >>> 0
会发生这种情况,如果真的发生了,是否真的希望将其转移到4294967295?似乎这样会使循环运行所需的次数。
this.length
知道它的实现是不可能的。对于任何“合理”的实现,字符串的长度都不应为负,但是有人可能会争辩说,在“合理”的环境中,我们可以假设存在this.length
总是返回整数的属性。
两个原因:
>>>的结果是一个“整数”
未定义>>> 0 = 0(因为JS会尝试将LFS强制转换为数字上下文,所以这同样适用于“ foo” >>> 0,依此类推)
请记住,JS中的数字的内部表示形式为double。这只是基本输入合理性的一种“快速”方式。
但是,-1 >>> 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