什么是JavaScript的 >>> 运算符,如何使用它?
JavaScript中的>>>操作符是无符号右移位操作符。与有符号右移位操作符的区别在于,无符号右移位操作符(>>>)从左侧用0填充,而有符号右移位操作符(>>)从符号位填充,从而保留数值在移位时的符号。
通常来说,将一个值向右移动0位是没有意义的。但是在JavaScript中,可能有一些特殊的含义。虽然我不是JavaScript专家,但这可能是一种确保该值实际上是一个整数的方式,因为JavaScript是一种无类型语言。
请参考下面Justin的答案。这实际上是一种确保len变量包含一个数字的方法。
此外,>>>操作符将值转换为整数,而一元操作符+不会进行这样的转换。
this.length >>> 0将有符号整数转换为无符号整数。个人而言,当加载包含无符号整数的二进制文件时,我发现这非常有用。
JavaScript中的无符号右移运算符在Mozilla的所有“数组扩展”方法实现中使用,以确保length属性是一个无符号的32位整数。
数组对象的length属性在规范中被描述为:
每个数组对象都有一个length属性,其值始终为小于2^32的非负整数。
这个运算符是实现这一目标的最简单方法,内部数组方法使用ToUint32操作,但该方法对外部不可访问,并且在规范中仅用于实现目的。
Mozilla的“数组扩展”实现试图遵守ECMAScript 5规范,看看Array.prototype.indexOf方法的描述(§ 15.4.4.14):
1. 将O设置为以this值为参数调用ToObject的结果。
2. 将lenValue设置为以参数“length”调用O的[[Get]]内部方法的结果。
3. 将len设置为ToUint32(lenValue)。
可以看到,它们只是想要复现ToUint32方法的行为,以便在ES3实现中符合ES5规范,正如我之前所说的,无符号右移运算符是最简单的方法。
虽然链接的“数组扩展”实现可能是正确的(或接近正确的),但代码仍然是一个糟糕的代码示例。也许甚至可以通过添加注释来澄清意图来解决这个问题。
数组的长度可能不是整数吗?我无法想象这种情况,所以这种ToUint32似乎有点不必要。
请记住,大多数Array.prototype方法是有意地通用的,它们可以用于类似数组的对象,例如Array.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1; arguments对象也是一个很好的例子。对于纯粹的数组对象,无法更改length属性的类型,因为它们实现了一个特殊的[[Put]]内部方法,当对length属性进行赋值时,它会再次被转换为ToUint32,并且会执行其他操作,例如删除新长度以上的索引...
JavaScript中的>>>运算符是什么以及如何使用它?
JavaScript的数字是双精度浮点数,但是位运算符(<<、>>、&、|和~)是基于32位整数的操作定义的。进行位运算将数字转换为32位有符号整数,丢失任何小数和比32位高的位,然后进行计算,最后再转换回数字。
因此,进行位运算,例如将0位右移>>0,是一种快速舍入数字并确保它在32位整数范围内的方法。此外,三个>>>运算符,在执行无符号操作后,将计算结果转换为Number类型的无符号整数,而不是其他运算符所做的有符号整数。因此,可以使用>>>0将负数转换为32位二进制补码表示的大整数。使用>>>0可以确保你得到一个介于0和0xFFFFFFFF之间的整数。
在这种情况下,这是有用的,因为ECMAScript将数组索引定义为32位无符号整数。因此,如果您想以完全复制ECMAScript第五版标准所说的方式来实现array.filter,您将以这种方式将数字转换为32位无符号整数。
实际上,很少有实际需要使用到这个方法,因为希望人们不会将array.length设置为0.5、-1、1e21或'LEMONS'。
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
由于array.length会自我验证,并且不能任意设置为非整数或0(例如,FF抛出错误:RangeError: invalid array length
),因此对于array.length,会有+2的深度描述和表格,-1。
然而,规范故意允许对许多Array函数进行调用,即使在非Array上(例如通过Array.prototype.filter.call
),所以array可能实际上并不是一个真正的Array,它可能是一些其他用户定义的类(不幸的是,它不能可靠地是一个NodeList,这是您真正想要做的,因为那是一个宿主对象。这样,您可能只会在arguments
伪数组中实际执行该操作的地方)。