9

编辑:此问题已过时,因为 Polyfill 示例已更新。我将问题留在这里仅供参考。阅读正确答案以获取有关按位移位运算符的有用信息。


问题:

在 Mozilla Array.prototype.indexOf页面的 Polyfill 示例中的第 7 行,他们对此进行了评论:

var length = this.length >>> 0; // Hack to convert object.length to a UInt32

但是 Mozilla 上的按位移位规范明确指出,运算符返回与左操作数相同类型的值:

移位运算符将其操作数转换为 32 位整数,并返回与左操作数相同类型的结果。

那么 length 不应该接收标准的 64 位浮点值吗?或者有人可以向我指出黑客从哪里开始?

4

3 回答 3

11

ECMAScript 规范声明该值在http://www.ecma-international.org/ecma-262/5.1/#sec-11.7的第 5 步和第 8 步中转换为 UInt32 :

11.7.3 无符号右移运算符( >>> )

对左操作数按右操作数指定的量 > 执行零填充按位右移操作。

生产ShiftExpression : ShiftExpression >>> AdditiveExpression评估如下:

  1. lref是评估的结果ShiftExpression
  2. 让。lval_GetValue(lref)
  3. rref是评估的结果AdditiveExpression
  4. 让。rval_GetValue(rref)
  5. lnumToUint32(lval)_
  6. 让。rnum_ToUint32(rval)
  7. shiftCount成为屏蔽除 的最低有效 5 位(rnum即计算 )之外的所有结果的结果rnum & 0x1F
  8. lnum返回按位执行零填充右移的结果shiftCount。空出的位用零填充。结果是一个无符号的 32 位整数
于 2014-03-11T20:28:07.777 回答
2

结果确实被转换回一个数字,即一个 64 位精度的浮点数。但是,在它被转换回来之前,两个操作数都被转换为UInt32,然后执行右移操作。这在 ECMAScript 中指定:http: //www.ecma-international.org/ecma-262/5.1/#sec-11.7.3

length >>> 0因此,由于>>> 0其本身是无操作的,因此的最终结果是先转换length为 a,UInt32然后再转换为 double。到底有什么好处呢?它强制损失精度,并有效地将值强制为 1) 和整数和 2) 在 [0, 2^32-1] 范围内。例如,如果是 -1,它将变为 2^32-1 == 4294967295。如果是 3.6,它将变为 3。

于 2014-03-11T20:33:38.777 回答
0

如果你运行这个测试,Math.floor 也会做同样的事情。如果你想在一个月左右的时间内理解自己的代码,那么应该避免这些黑客攻击。

var a=3.6, b = a >>> 0;
console.log(b);
console.log(Math.floor(a));
于 2014-06-05T15:34:16.240 回答