关于javascript:为什么在if语句中使用双惊叹号?

Why use double exclamation marks in an if statement?

我最近读了一些代码,它使用!!将变量转换为布尔值,以便在if语句中进行计算。这对我来说似乎有点多余,因为无论如何都要对变量的布尔值进行评估。这样做有什么性能上的好处吗?还是为了更好地支持浏览器?

样例代码:

1
2
3
4
5
var x = 0;
var atTop = x===window.scrollY;
if(!!atTop){
   alert("At the top of the page.");
}

编辑:

我也看到过对于不属于布尔类型的操作数的这种情况,但我一直假设使用if可以无论如何评估变量的布尔值,因为javascript中的所有值都是"真的"或"假的"。

样例代码:

1
2
3
4
5
var x = 1;//or any other value including null, undefined, some string, etc
if(!!x){//x is"truthy"
   //wouldn't using if(x) be the same???
   console.log("something...");
}


简短回答:不,没有理由。

在您的代码中,它已经是一个boolean类型,不需要转换它,然后再转换回来,您将得到相同的结果。实际上,如果您有任何布尔值(truefalse),当您对其中任何一个使用!!时,它将被转换回它的初始值:

1
2
3
4
console.log(!!true); // Will be always"true"
console.log(typeof !!true); // It stills a"boolean" type
console.log(!!false); // Will be always"false"
console.log(typeof !!false); // It stills a"boolean" type

编辑过的问题的答案:是的,是一样的。这就是if(...)实际所做的——它试图将任何类型转换为boolean

这里有一个小测试,你可以在initialArr数组中随意添加你想要的东西进行测试,它与if!!的行为是否相同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const initialArr = [
  undefined,
  null,
  true,
  false,
  0,
  3,
  -1,
  +Infinity,
  -Infinity,
  Infinity,
  'any',
  '',
  function() { return 1 },
  {},
  { prop: 1 },
  [],
  [0],
  [0, 1]
];

function testIsTheSame(arr) {
  equolityCounter = 0;
  arr.forEach(item => {
    let ifStatement = false;
    let doubleNotStatement = !!item;
    if(item) {
      ifStatement = true;
    }

    if(ifStatement === doubleNotStatement && typeof ifStatement === typeof doubleNotStatement) {
      equolityCounter++;
    }
  });
  console.log(`Is the same: ${equolityCounter === arr.length}`);
}

testIsTheSame(initialArr);


我会说这主要是为了代码的可读性。我怀疑是否存在任何重要的性能或兼容性影响(请有人自由测试)

但是在代码可读性方面,这意味着以前这个变量不是一个布尔值,但是我们希望将它作为一个变量来计算,如果您添加了有关这个变量的新逻辑,请记住这一点。

虽然在你的例子中,它已经是布尔型的,所以它是100%冗余的,但我想这只是一个习惯,有人对上面的推理过度应用,和/或看到它在其他地方和复制模式,而没有完全理解它(短篇小说时间:在c中,你可以通过添加@来命名一个受保护的术语一个变量名,所以var @class ="hello";,一个Junior Dev只是假设所有变量名前面都需要@,并用这种方式编码。我想知道是否有人假设没有比较运算符的if需要将!!作为比较运算符放在它前面)


这完全取决于atTop变量的值。按照这里的讨论。

总之,如果EDOCX1的值(13)与EDOCX1的值(0)有任何不同,则第一个负数将其转换为布尔值(负数)。第二个否定将布尔值返回到原始atTop值的等效布尔值。

例如,如果atTopundefined,首先!将其转换为boolean true,然后第二个!将其转换为boolean false(这将是undefined的等价布尔值)。

但是,在代码中,atTop值是严格相等===的结果,这意味着在atTop中总是得到一个布尔值。因此,不需要将非布尔值转换为布尔值,因此不需要!!


在if语句中这样做没有任何运行时好处(或目标好处)。if语句执行的计算将产生与双感叹号生成的计算完全相同的结果。没有区别。

双感叹号是确保基于真实性的布尔值的有用表达式。例如,考虑:

1
2
3
4
5
6
7
8
9
10
var text = undefined;
console.log(text); // undefined
console.log(!!text); // false

// It would make sense here, because a boolean value is expected.
var isTextDefined = !!text;

// It would also affect serialization
JSON.stringify(text); // undefined (non-string)
JSON.stringify(!!text); //"false"

我认为这是由于上述用例而养成的一种习惯,因此在希望解决变量的真实性时,总是转换为布尔值。当规则总是被应用时,我们(人类和程序员)更容易遵循它。你可以一直使用车内的闪光灯,即使周围没有人,也可以偶尔(或经常)忘记发出信号。