有人可以解释这个“双重否定”的伎俩吗?

我绝不是JavaScript的专家,但我一直在阅读Mark Pilgrim的“潜入HTML5”网页,他提到了一些我想要更好的理解的东西。

他指出:

最后,您使用双重否定技巧强制结果为布尔值(true或false)。

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

如果有人能更好地解释这一点,我将不胜感激!

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

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

从逻辑NOT运算符的这些文档 :

如果其单个操作数可以转换为true,则返回false; 否则,返回true。

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

“错误”的价值是:

  • false
  • NaN
  • undefined
  • null
  • "" (空string)
  • 0

如果放置在期望布尔值的上下文中,那么Javascript对于被认为是“真”和“假”的规则会有一些混淆。 但逻辑NOT运算符! 总是产生一个合适的布尔值(其中一个常量truefalse )。 通过链接它们中的两个,成语!!expression产生与原始expression式相同的真实性的适当的布尔值。

你为什么打扰? 因为它使function像你显示更可预测的function。 如果在那里没有双重否定,它可能会返回undefined ,一个Function对象,或者与Function对象完全不同的东西。 如果这个函数的调用者用返回值做了一些奇怪的事情,那么整个代码可能会行为不端(这里的“怪异”意思是“除了强制布尔上下文的操作之外的任何事情”)。 双重负面的习语可以防止这种情况发生。

在JavaScript中,如果给定值为真,则使用“bang”运算符(!)将返回true,如果值为undefined,null,0或空string,则返回false。

所以bang运算符总是会返回一个布尔值,但是它会代表你开始的相反的值。 如果你把这个操作的结果再次“敲打”一遍,你可以反转一遍,但是最后还是一个布尔值(而不是未定义的,null等)。

使用bang两次将会得到一个可能未定义的值,null等等,并且只是简单的false 。 这将需要一个值,可能是1,“真实”等,并使其显然是true

代码可以写成:

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

使用!!variables可以保证types转换为布尔值。

给你一个简单的例子:

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

但是,如果你正在做类似的事情,那么使用它是没有意义的:

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

if会将其转换为布尔值,因此不需要进行隐式双重负投。

! 将“something”/“anything”转换为boolean

!! 给出原来的布尔值(并保证expression式是一个布尔值,不pipe之前是什么)

第一! 强制该variables为布尔types并将其反转。 第二! 再次翻转它(给你原来的(正确的)布尔值,无论你正在检查)。

为了清楚起见,你最好使用

 return Boolean(....); 

document.createElement('canvas').getContext可能会评估为undefined或对象引用。 !undefined yield true![some_object]产生false 。 这几乎是我们所需要的,只是倒过来。 所以!! 用于将undefined转换为false并将对象引用转换为true

这与JavaScript的弱types有关。 document.createElement('canvas').getContext是一个函数对象。 通过预先一个! 它评估它作为一个布尔expression式,并翻转周围的答案。 通过预先计划另一个! ,它翻转答案。 最终结果是该函数将其评估为布尔expression式,但返回实际的布尔结果而不是函数对象本身。 预先!! 是一种将expression式转换为布尔types的快速且肮脏的方法。

如果document.createElement('canvas').getContext不是undefined或为null ,则返回true 。 否则,它将返回false