关于javascript:有人能解释这个”双重否定”的技巧吗?

Can someone explain this 'double negative' trick?

本问题已经有最佳答案,请猛点这里访问。

我绝对不是javascript专家,但我一直在阅读MarkPilger的"潜入HTML5"网页,他提到了一些我想更好理解的东西。

他说:

Finally, you use the double-negative trick to force the result to a Boolean value (true or false).

1
2
3
function supports_canvas() {
  return !!document.createElement('canvas').getContext;
}

如果有人能更好地解释这一点,我会感激的!


逻辑非运算符!将值转换为与其逻辑值相反的布尔值。

第二个!将前一个布尔结果转换回其原始逻辑值的布尔表示。

对于逻辑非运算符,从这些文档中:

Returns false if its single operand can be converted to true; otherwise, returns true.

所以如果getContext给你一个"假"值,!!会使它返回布尔值false。否则将返回true

"虚假"值为:

  • false
  • NaN
  • undefined
  • null
  • ""(空字符串)
  • 0


当把javascript放在一个需要布尔值的上下文中时,它对于被认为是"真"和"假"的内容有一套令人困惑的规则。但是逻辑非运算符!总是产生一个适当的布尔值(truefalse常量之一)。通过链接其中的两个,习语!!expression产生了一个与原始表达式具有相同真实性的布尔值。

你为什么要麻烦?因为它使你所展示的功能更具可预测性。如果没有双负,它可能返回undefinedFunction对象,或者与Function对象完全不同的对象。如果这个函数的调用者对返回值做了一些奇怪的事情,那么整个代码可能会出现错误行为("奇怪"这里的意思是"除了强制布尔上下文的操作之外的任何操作")。双重否定成语阻止了这一点。


在javascript中,使用"bang"运算符!!)如果给定值为真、1、非空等,则返回真。如果该值为未定义、空、0或空字符串,则返回假。

所以bang运算符总是返回一个布尔值,但它将表示与您开始使用的值相反的值。如果您得到该操作的结果并再次"砰"地一声,您可以再次反转它,但最终仍然得到一个布尔值(而不是未定义、空值等)。

使用bang两次将得到一个可能未定义、空值等的值,并使其变为普通的false。它需要一个可能是1的值,"真的",等等,并使它变得简单。

代码可以写在:

1
2
3
4
var context = document.createElement('canvas').getContext;
var contextDoesNotExist = !context;
var contextExists = !contextDoesNotExist;
return contextExists;

使用!!variable保证将类型转换为布尔型。

举个简单的例子:

1
2
3
4
5
"" == false (is true)
"" === false (is false)

!!"" == false (is true)
!!"" === false (is true)

但是,如果你在做如下的事情,使用它是没有意义的:

1
2
3
var a =""; // or a = null; or a = undefined ...
if(!!a){
...

if将其强制转换为布尔值,因此不需要进行隐式的双负强制转换。


!boolean投射"某物"/"任何东西"。

!!返回原始布尔值(并保证表达式现在是布尔值,不管以前是什么)


第一个!将变量强制为布尔类型并将其反转。第二个!再次反转它(为您检查的内容提供原始(正确)布尔值)。

为了清楚起见,最好使用

1
return Boolean(....);


document.createElement('canvas').getContext可以对undefined或对象引用进行评估。!undefined生成true![some_object]生成false。这几乎是我们需要的,只是颠倒过来。因此,!!用于将undefined转换为false和对象引用true


这与javascript的弱类型有关。document.createElement('canvas').getContext是一个函数对象。通过预先准备单个!,它将其评估为布尔表达式,并翻转答案。通过预先准备另一个!,它会翻转答案。最终结果是,函数将其作为布尔表达式计算,但返回实际的布尔结果,而不是函数对象本身。预处理!!是将表达式类型转换为布尔类型的一种快速而肮脏的方法。


如果document.createElement('canvas').getContext不是undefinednull的话,它将返回true。否则返回false