為什麼999.222<<0 會得到整數999 ? javascript

利用這段代碼
color = "#"+ (Math.random()*0xffffff<<0).toString(16);
實現了隨機得到顏色

但是實在不明白為什麼?

這裡有解釋到一點 但也不明白
http://www.cnblogs.com/rubylo...

基本实现4的改进,利用左移运算符把0xffffff转化为整型。这样就不用记16777215了。由于左移运算符的优先级比不上乘号,因此随机后再左移,连Math.floor也不用了。

如果x.abcd << 0 這樣也可以得到整數 x ,那又和Math.floor(x.abcd) 有什麼差別呢?

阅读 2.8k
3 个回答

这种问题,看规范就知道啦

移位运算在内部是啥样的?

12.8.3.1 Runtime Semantics: Evaluation

ShiftExpression : ShiftExpression << AdditiveExpression

  1. Let lref be the result of evaluating ShiftExpression.

  2. Let lval be GetValue(lref).

  3. ReturnIfAbrupt(lval).

  4. Let rref be the result of evaluating AdditiveExpression.

  5. Let rval be GetValue(rref).

  6. ReturnIfAbrupt(rval).

  7. Let lnum be ToInt32(lval).

  8. ReturnIfAbrupt(lnum).

  9. Let rnum be ToUint32(rval).

  10. ReturnIfAbrupt(rnum).

  11. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.

  12. Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.

关键就是我标红的那一步,这一步会把变量lvalToInt32的运算,而这个lval就是来自我们移位运算的左值,就是你的999.222

接下来,再来看看ToInt32做了啥:

7.1.5 ToInt32 ( argument )

The abstract operation ToInt32 converts argument to one of 2^32 integer values in the range −2^31 through 2^31−1, inclusive. This abstract operation functions as follows:

  1. Let number be ToNumber(argument).

  2. ReturnIfAbrupt(number).

  3. If number is NaN, +0, −0, +∞, or −∞, return +0.

  4. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).

  5. Let int32bit be int modulo 2^32.

  6. If int32bit ≥ 2^31, return int32bit − 2^32, otherwise return int32bit.

关键的那步我也给你标出来了,这里会把输入值直接取整。
所以,给一个浮点数做0的移位运算,结果就是取整。

对于Math.floor,规范没说具体实现,只给了一句话——

Returns the greatest (closest to +∞) Number value that is not greater than x and is equal to a mathematical integer. If x is already an integer, the result is x.
返回不大于x的最大整数;假如x已经是整数了,那么返回x

Math.floor的实现没给出,但是移位取整中间还多了好几个步骤,除了写代码的时候能稍微简洁一点以外,我觉得还是Math.floor更好点。

另外,ToInt32里面的那个floor运算是这么实现的:

floor(x) = x−(x modulo 1)

modulo是取模运算的意思,x1取模,那就是求x的小数部分,随后x剪掉了自己的小数部分,那就剩下整数了嘛。

必须要注意的是,ToInt32中是先取绝对值然后再取整的,所以在负数区间内,<< 0Math.floor的结果是不一样的。
Math.floor返回的是不大于输入值的最大整数,那么肯定就有Math.floor(-1.5) = -2
而对于<< 0运算,它是先取绝对值,然后取整,最后再把符号弄回去,那么就有-1.5 << 0 = -1

不了解这个运算符原理,但是之前看到过~~这个运算符的用法,试了一下发现类似
图片描述
图片描述

都是对负数相当于Math.ceil对正数相当于Math.floor
会快,但是写法比较hack

位运算的安全值是32位整数,超过32位的会被忽略,小数部分也被忽略
x.abcd << 0 直接丢弃了小数部分 ,Math.floor(x.abcd) 向下取整,它们的算法不同
当x.abcd为负数时就能区分开了,如:
-5.8<<0; //5
Math.floor(-5.8); //-6

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题