JavaScript 中的“双波浪号”(~~)运算符是什么?

IT技术 javascript
2021-01-19 19:04:23

我在一些代码中看到了这一点,但我不知道它是做什么的:

var jdn = function(y, m, d) {
  var tmp = (m <= 2 ? -1 : 0);
  return ~~((1461 * (y + 4800 + tmp)) / 4) + 
         ~~((367 * (m - 2 - 12 * tmp)) / 12) - 
         ~~((3 * ((y + 4900 + tmp) / 100)) / 4) + 
         d - 2483620;
};

~~运营商是做什么的

4个回答

~~是一个双非按位运算符。

它是用来作为一个更快的替代品Math.floor()正面数字。它不会返回与Math.floor()负数相同的结果,因为它只是截断了小数点后的部分(有关此示例,请参阅其他答案)。

我使用这种技术处理非常大的数字时遇到了整数溢出问题(在 base-62 编码期间将来自 Navigation Timing API 的数字除以 62 的结果)。例如,在 Firefox、Chrome 和 IE 中,~~(2419354838.709677) == -1875612458,而 Math.floor(2419354838.709677) == 2419354838。
2021-03-12 19:04:23
不要用~~!在 IE10 中,它比对同一件事执行其他按位运算慢 8 倍!最好使用零右移 (>>0),它是最快的,看起来更类似于有符号到无符号转换 (>>>0)。
2021-03-19 19:04:23
@ghoppe:值得注意的是,它的不同之处.floor()在于它实际上只是删除了小数点右侧的任何内容。当用于负数时,这会有所不同。此外,它总是会返回一个数字,并且永远不会给你NaN如果它不能转换为数字,你会得到0.
2021-03-21 19:04:23
@ghoppe:是的,两个 not 操作实际上比单层方法更快。当我在计算机上的 Firefox 中对其进行测试时,它们的运行时间约为 0.2 微秒,而不是 0.5 微秒。这意味着您需要多次使用它才能引起注意。在像 OP 那样的函数中,它只是微优化,只会使代码更难遵循。
2021-03-22 19:04:23
类似于 Math.trunc(),但不是 Math.floor()
2021-03-25 19:04:23

它隐藏了代码的意图。

它是两个单波浪号运算符,因此它进行了两次按位补码(按位不加)。操作相互取出,所以唯一剩下的效果是在应用第一个运算符之前完成的转换,即将值转换为整数。

有些人将其用作 的更快替代品Math.floor,但速度差异并不那么显着,在大多数情况下,这只是微优化。除非您有一段真正需要优化的代码,否则您应该使用描述其功能的代码,而不是使用非操作副作用的代码。

2011-08 更新:

随着浏览器中 JavaScript 引擎的优化,运算符和函数的性能发生了变化。对于当前的浏览器,在某些浏览器中使用~~而不是Math.floor更快一些,而在某些浏览器中则根本不快。如果您真的需要额外的性能,则需要为每个浏览器编写不同的优化代码。

请参阅:波浪号与地板

为什么 Chrome 22 比 Chrome 8 慢这么多??
2021-03-14 19:04:23
请记住 Math.floor() 的存在是有原因的。如果您不了解它可能导致溢出或其他意外结果的位置,请不要使用 ~~ 因为它比 Math.floor 快 2 微秒。
2021-03-17 19:04:23
+1 表示“它隐藏了代码的意图”,我浪费了 10 分钟才知道是什么~~无论如何,我也不得不承认它已经很强大了,我的阴暗面已经诱使我现在在我的新代码中使用它~~来代替Math.floor永远。:)))))
2021-03-19 19:04:23
请注意,像 JSPerf 这样的微测试(必须)运行测试代码的次数足够多,以至于动态运行时优化(例如在 V8 中)开始发挥作用。该测试表明(如果使用得非常频繁)Math.floor() 可以~~在 Chrome 上一样快,但并不是说它总是相同的速度。如今,很难确定某一位代码是否比另一位“更快”(考虑到不同的浏览器和调用场景)。
2021-03-24 19:04:23
@MattSach:只有在同一台计算机上测试,或者有足够多的人测试过,这些数字才具有可比性。Chrome 的版本如此之多,以至于很少有人测试过每个版本的代码。
2021-03-27 19:04:23
~(5.5)   // => -6
~(-6)    // => 5
~~5.5    // => 5  (same as Math.trunc(5.5) and Math.floor(5.5))
~~(-5.5) // => -5 (same as Math.trunc(-5.5) but NOT the same as Math.floor(-5.5), which would give -6 )

有关更多信息,请参阅:

Math.floor(-5.5),它将给出 -6。Bcos Math.floor 将返回小于或等于给定数字的最大整数。Math.floor(-5.00000001) 也给出 -6。
2021-04-01 19:04:23
~(-5.5)=> 4, ~(4)=> -5, ~~(-5.5)=> -5因此,不等同于Math.floor
2021-04-06 19:04:23
@zzzzBov,我更新了帖子以澄清这~~Math.floor()负数不同。
2021-04-08 19:04:23

区别很简单:

长版

如果您想获得更好的可读性,请使用Math.floor. 但是如果你想最小化它,使用波浪号~~

互联网上有很多来源说Math.floor更快,但有时~~我不建议您考虑速度,因为在运行代码时不会注意到它。也许在测试等中,但没有人可以看到这里的差异。更快的是使用~~更快的加载时间。

简洁版本

~~更短/占用更少的空间。Math.floor提高了可读性。有时波浪号更快,有时Math.floor更快,但并不明显。

对。它主要是一种风格选择,比如在 Boolean(foo)、(foo ? true : false) 或 !!foo 之间进行选择,当您想将变量转换为布尔值时。
2021-03-27 19:04:23
Math.trunc(),而不是 Math.floor()
2021-04-07 19:04:23