什么是JavaScript>>>操作员以及如何使用它?

时间:2009-11-30 20:59:01

标签: javascript operators bit-shift

我正在查看Mozilla的代码,它为Array添加了一个过滤方法,它有一行代码使我感到困惑。

var len = this.length >>> 0;

我从未见过>>>之前在JavaScript中使用过。
它是什么,它做了什么?

7 个答案:

答案 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-11e21或{{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建议不要使用这些东西)。这并不意味着它做错了,但是存在更有利和熟悉的方法来使代码更具可读性。确保len0的更明确方法是以下两种方法之一。

// 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。不过,我认为这个例子是一个讨厌的黑客,原因有两个:

  1. 使用负数时<<<的行为,在上面的示例中可能没有(或可能发生)副作用。

  2. 代码的意图不明显,因为此问题的存在会验证。

  3. 最佳做法可能是使用更具可读性的东西,除非性能绝对至关重要:

    isNaN(parseInt(foo)) ? 0 : parseInt(foo)
    

答案 5 :(得分:10)

有两个原因:

  1. &gt;&gt;&gt;的结果是一个“积分”

  2. undefined&gt;&gt;&gt; 0 = 0(因为JS会尝试将LFS强制转换为数字上下文,这也适用于“foo”&gt;&gt;&gt; 0等等)

  3. 请记住,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