有人能解释一下这个“双重否定”的把戏吗?

IT技术 javascript html
2021-01-19 20:26:34

我绝不是 Javascript 方面的专家,但我一直在阅读 Mark Pilgrim 的“Dive into HTML5”网页,他提到了一些我希望更好地理解的内容。

他说:

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

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

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

6个回答

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

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

来自这些逻辑非运算符的文档

如果它的单个操作数可以转换为真,则返回假;否则,返回真。

因此,如果getContext给您一个“falsey”值,!! 它将使其返回布尔值false否则它会返回true

“falsey”值是:

  • false
  • NaN
  • undefined
  • null
  • "" (空字符串)
  • 0
@Grinn:user113716 没有列出所有内容。他忘记了 -0 。我的意思不是一元减零,而是一个单独值的结果。例如,您可以通过将 -0 分配给变量来创建它。
2021-03-15 20:26:34
@MarcodeWit:它们在 JavaScript 中是相等的值。-0 === 0 // trueuser113716 没有错过与问题相关的任何内容。
2021-03-15 20:26:34
@squint:首先,user113716 试图重现虚假值列表,但我仍然认为其中缺少 -0。我认为这与存在的问题有关,因为也许有人会认为如果 0 为假,则 -0 由于减号而再次变为真。-0 === 0 仅评估为真,因为它是这样定义的,而不是因为相同类型的相等值。此外,如果它们真的相等,那么 1/0 应该给出与 1/-0 相同的结果。
2021-03-21 20:26:34
@MarcodeWit:用户可能会这么认为,但没有理由这么认为。这个问题是关于逻辑操作的,而且0总是错误的。这就是他的回答所说的。 -0 === 0显示它们相同类型的相等值,因为它是这样定义的。您的除法示例是一个非常具体的情况,与此问题或该0值的99.999% 的用途无关oop,甚至.toString()以同样的方式代表他们。(-0).toString(); // "0"
2021-03-25 20:26:34
Object.is(0, -0)返回false,所以它们不是一回事。
2021-04-13 20:26:34

当放置在需要布尔值的上下文中时,Javascript 对什么被认为是“真”和“假”有一组令人困惑的规则。但是逻辑非运算符 ,!总是产生一个正确的布尔值(常量true和 之一false)。通过链接它们中的两个,习语!!expression产生了一个与原始表达式具有相同真实性的正确布尔值。

你为什么要打扰?因为它使您展示的功能更加可预测。如果那里没有双重否定,它可能会返回undefined一个Function对象,或者与Function对象完全不同的东西如果这个函数的调用者对返回值做了一些奇怪的事情,整个代码可能会出错(“奇怪”在这里意味着“除了强制执行布尔上下文的操作之外的任何事情”)。双重否定的习语阻止了这一点。

无论如何,我并不是有意强烈反对。
2021-03-21 20:26:34
当然:这是一个列表,而不是规则。我认为它是否令人困惑是非常主观的。我个人认为在转换为布尔值时知道什么是“虚假”和什么是“真实”是非常直观的。
2021-03-24 20:26:34
@Abody97 列表(上面显示的很有帮助)既不是尽可能短(false;其他任何东西都需要显式比较运算符),也不是尽可能长(至少添加{}[])。所以你必须记住列表而不是规则。这就是我所说的令人困惑的语言功能。
2021-03-30 20:26:34
这不是一套“令人困惑”的规则。
2021-04-12 20:26:34

在 javascript 中,如果给定值是真、1、非空等,使用“bang”运算符 (!) 将返回真。如果值是未定义、空、0 或空字符串,它将返回假。

因此 bang 运算符将始终返回一个布尔值,但它将表示与您开始时相反的值。如果您获取该操作的结果并再次“敲打”它,您可以再次反转它,但最终仍会得到一个布尔值(而不是未定义、空值等)。

使用 bang 两次将采用一个可能是 undefined、null 等的值,并使其变得简单false它将采用一个可能是 1、“true”等的值,并使其变得简单true

代码可以写成:

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

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

给你一个简单的例子:

"" == 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.

!! 返回原始布尔值(并保证表达式现在是布尔值,无论之前是什么)