JavaScript 是什么>>>>运算符以及如何使用它?

发布于 2024-09-11 20:39:19 字数 187 浏览 5 评论 0原文

我正在查看 Mozilla 中向 Array 添加过滤方法的代码,其中有一行代码让我感到困惑。

var len = this.length >>> 0;

我从来没见过>>>>之前在 JavaScript 中使用过。
它是什么以及它有什么作用?

I was looking at code from Mozilla that add a filter method to Array and it had a line of code that confused me.

var len = this.length >>> 0;

I have never seen >>> used in JavaScript before.
What is it and what does it do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

長街聽風 2024-09-18 20:39:19

它不仅将非数字转换为数字,还将它们转换为可以表示为 32 位无符号整数的数字。

尽管 JavaScript 的数字是双精度浮点数 (*),但按位运算符 (<<>>&|~) 是根据 32 位整数的运算来定义的。执行按位运算会将数字转换为 32 位有符号整型,丢失所有小数和高于 32 的位,然后再进行计算,然后转换回 Number。

因此,进行没有实际效果的按位运算,例如右移 0 位 >>0,是一种快速舍入数字并确保其位于 32 位 int 范围内的方法。另外,三重 >>> 运算符在执行无符号运算后,将其计算结果转换为 Number 作为无符号整数,而不是其他运算符所做的有符号整数,因此可以用于将负数转换为 32 位二进制补码版本作为大数。使用 >>>0 可确保您获得 0 到 0xFFFFFFFF 之间的整数。

在这种情况下,这很有用,因为 ECMAScript 根据 32 位无符号整数定义数组索引。因此,如果您尝试以完全重复 ECMAScript 第五版标准所述的方式实现 array.filter,则可以将数字转换为 32 位无符号 int,如下所示。

实际上,这几乎没有实际需要,因为希望人们不会将 array.length 设置为 0.5-11e21'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

(*:嗯,它们被定义为像浮点数一样。如果出于性能原因,某些 JavaScript 引擎实际上在可能的情况下使用了整数,我不会感到惊讶。但这将是您无法了解的实现细节充分利用任何优势。)

It doesn't just convert non-Numbers to Number, it converts them to Numbers that can be expressed as 32-bit unsigned ints.

Although JavaScript's Numbers are double-precision floats(*), the bitwise operators (<<, >>, &, | and ~) are defined in terms of operations on 32-bit integers. Doing a bitwise operation converts the number to a 32-bit signed int, losing any fractions and higher-place bits than 32, before doing the calculation and then converting back to Number.

So doing a bitwise operation with no actual effect, like a rightward-shift of 0 bits >>0, is a quick way to round a number and ensure it is in the 32-bit int range. Additionally, the triple >>> operator, after doing its unsigned operation, converts the results of its calculation to Number as an unsigned integer rather than the signed integer the others do, so it can be used to convert negatives to the 32-bit-two's-complement version as a large Number. Using >>>0 ensures you've got an integer between 0 and 0xFFFFFFFF.

In this case this is useful because ECMAScript defines Array indexes in terms of 32 bit unsigned ints. So if you're trying to implement array.filter in a way that exactly duplicates what the ECMAScript Fifth Edition standard says, you would cast the number to 32-bit unsigned int like this.

In reality there's little practical need for this as hopefully people aren't going to be setting array.length to 0.5, -1, 1e21 or 'LEMONS'.

Summary:

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

(*: well, they're defined as behaving like floats. It wouldn't surprise me if some JavaScript engine actually used ints when it could, for performance reasons. But that would be an implementation detail you wouldn't get to take any advantage of.)

瑶笙 2024-09-18 20:39:19

Mozilla 的所有array extra方法实现中都使用无符号右移运算符,以确保length属性是无符号32位整数嗯>。

数组对象的 length 属性在描述规格为:

每个 Array 对象都有一个 length 属性,其值始终是小于 232 的非负整数。

此运算符是实现它的最短方法,内部数组方法使用 ToUint32< /code>操作,但该方法不可访问并且存在于用于实现目的的规范中。

Mozilla array 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 规范,正如我之前所说, 无符号右移运算符是最简单的方法。

The unsigned right shift operator is used in the all the array extra's method implementations of Mozilla, to ensure that the length property is a unsigned 32-bit integer.

The length property of array objects is described in the specification as:

Every Array object has a length property whose value is always a nonnegative integer less than 232.

This operator is the shortest way to achieve it, internally array methods use the ToUint32 operation, but that method is not accessible and exist on the specification for implementation purposes.

The Mozilla array extras implementations try to be ECMAScript 5 compliant, look at the description of the Array.prototype.indexOf method (§ 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).
....

As you can see, they just want to reproduce the behavior of the ToUint32 method to comply with the ES5 spec on an ES3 implementation, and as I said before, the unsigned right shift operator is the easiest way.

浅忆流年 2024-09-18 20:39:19

这是无符号右移运算符。它与有符号右位移运算符之间的区别在于无符号右位移运算符(>>>)从左侧填充零,而有符号右位移运算符( >>)用符号位填充,从而在移位时保留数值的符号。

That is the unsigned right bit shift operator. The difference between this and the signed right bit shift operator, is that the unsigned right bit shift operator (>>>) fills with zeroes from the left, and the signed right bit shift operator (>>) fills with the sign bit, thus preserving the sign of the numerical value when shifted.

苏璃陌 2024-09-18 20:39:19

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; 

Driis has sufficiently explained what the operator is and what it does. Here's the meaning behind it/why it was used:

Shifting any direction by 0 does returns the original number and will cast null to 0. It seems that the example code that you are looking at is using this.length >>> 0 to ensure that len is numeric even if this.length is not defined.

For many people, bitwise operations are unclear (and Douglas Crockford/jslint suggests against using such things). It doesn't mean that its wrong to do, but more favorable and familiar methods exist to make code more readable. A more clear way to ensure that len is 0 is either of the following two methods.

// Cast this.length to a number
var len = +this.length;

or

// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0; 
诗化ㄋ丶相逢 2024-09-18 20:39:19

>>>无符号右移运算符 (参见 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 。尽管如此,我认为这个例子是一个令人讨厌的黑客,原因有两个:

  1. 使用负数时<<<的行为,一边- 在上面的示例中,效果可能不是预期的(或可能发生)。

  2. 代码的意图并不明显,正如这个问题的存在所验证的那样。

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

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

>>> is the unsigned right shift operator (see p. 76 of the JavaScript 1.5 specification), as opposed to the >>, the signed right shift operator.

>>> changes the results of shifting negative numbers because it does not preserve the sign bit when shifting. The consequences of this is can be understood by example, from an interpretter:

$ 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

So what is probably intended to be done here is to get the length, or 0 if the length is undefined or not an integer, as per the "cabbage" example above. I think in this case it is safe to assume that this.length will never be < 0. Nevertheless, I would argue that this example is a nasty hack, for two reasons:

  1. The behavior of <<< when using negative numbers, a side-effect probably not intended (or likely to occur) in the example above.

  2. The intention of the code is not obvious, as the existence of this question verifies.

Best practice is probably to use something more readable unless performance is absolutely critical:

isNaN(parseInt(foo)) ? 0 : parseInt(foo)
冰魂雪魄 2024-09-18 20:39:19

两个原因:

  1. >>的结果是一个“积分”

  2. 未定义>>>>> 0 = 0(因为 JS 会尝试将 LFS 强制为数字上下文,这也适用于“foo”>>> 0 等)

请记住,JS 中的数字有一个 double 的内部表示。
这只是基本输入长度的“快速”方式。

但是,-1 >>> 0(哎呀,可能不是所需的长度!)

Two reasons:

  1. The result of >>> is an "integral"

  2. undefined >>> 0 = 0 (since JS will try and coerce the LFS to numeric context, this will work for "foo" >>> 0, etc. as well)

Remember that numbers in JS have an internal-representation of double.
It's just a "quick" way of basic input sanity for length.

However, -1 >>> 0 (oops, likely not a desired length!)

梦里寻她 2024-09-18 20:39:19

下面的示例 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

Sample Java Code below explains well:

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));

Output is the following:

x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文