JavaScript中的“双波浪线”(~~)操作符是什么?

688

我在一些代码中看到了这个,但我不知道它是什么意思:

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

什么是~~运算符的作用?


3
你可能已经明白了,但它返回公元纪年和给定日期之间的天数。 - Awalias
1
简单来说,它将'9'转换为数字9。而且即使在IE8中,它的速度比Math.floor()更快。 如果您在控制台中执行以下操作: typeof ~~'9'//number - STEEL
5
Math.trunc(),而不是Math.floor()。 - Xitalogy
4个回答

904

331
值得注意的是,它与 .floor() 不同之处在于它实际上只是删除小数点右侧的任何内容。当用于负数时,这会产生差异。此外,它始终会返回一个数字,并且永远不会给你 NaN。如果无法转换为数字,则会返回 0 - RightSaidFred
2
@Guffa 很好,测试页面是可编辑的,这样就好了。 :) 我刚刚测试了一下,在Safari 5上,~~Math.floor快两倍。 - ghoppe
35
使用这种技术处理非常大的数字时(通过Navigation Timing API中的数字除以62进行基于62的编码),我遇到了整数溢出问题。例如,在Firefox、Chrome和IE中,~~(2419354838.709677)的结果为-1875612458,而Math.floor(2419354838.709677)的结果是2419354838。 - Jacob Wan
11
类似于Math.trunc(),但不同于Math.floor()。 - Xitalogy
6
虽然~~是Math.floor()的速记方式,-~是Math.ceil()的速记方式。 - Junaid Anwar
显示剩余8条评论

222

它隐藏了代码的意图。

这是两个单波浪线运算符,因此它执行一次按位补码(按位取反)两次。这些操作互相抵消,因此唯一剩下的效果是在应用第一个运算符之前进行的转换,即将值转换为整数。

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

更新 2011-08:

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

参见:tilde vs floor


135
对于“它隐藏了代码的意图”,我点赞,我浪费了10分钟才知道~~的作用。无论如何,我也不得不承认在我内心深处已经有一种诱人使用~~而不是Math.floor的黑暗力量了,这可能会影响我的新代码 :)))) - Marco Demaio
2
请注意,像JSPerf这样的微型测试必须运行足够多次的测试代码,以便即时运行时优化(例如在V8中)启动。该测试表明(如果非常频繁地使用),Math.floor()在Chrome上可以与~~一样快,但并不意味着它总是相同的速度。如今,很难确定一个代码片段是否比另一个“更快”(考虑到不同的浏览器和调用场景)。 - Phrogz
1
为什么Chrome 22比Chrome 8慢那么多? - Matt Sach
8
记住,Math.floor() 的存在是有原因的。如果你不理解使用可能会导致溢出或其他意外结果时,请不要仅仅为了比Math.floor()快2微秒而使用 - dudewad
这个差距对于Chrome来说已经显著缩小了。https://jsperf.com/math-floor-vs-math-round-vs-parseint/183 - Graham P Heath
显示剩余4条评论

173
~(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 )

了解更多信息,请参见:


14
~(-5.5) 等于 4~(4) 等于 -5~~(-5.5) 等于 -5。因此,这与 Math.floor 不同。 - zzzzBov
1
@zzzzBov,我更新了帖子以澄清~~与负数的Math.floor()不同。 - bowsersenior
Math.floor(-5.5) 的结果为 -6。因为 Math.floor 会返回小于或等于给定数字的最大整数。Math.floor(-5.00000001) 的结果也是 -6。 - SridharKritha

25

区别很简单:

长版

如果您想要更好的可读性,请使用Math.floor。但是,如果您想要最小化代码,则使用波浪线符号~~

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

短版

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


6
好的,这主要是一种风格选择,就像在将变量转换为布尔值时,选择使用Boolean(foo)、(foo ? true : false)或!!foo一样。 - Patrick Fisher
19
Math.trunc(),不是Math.floor()。 - Xitalogy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接