JavaScript中的!运算符

16

我现在对JavaScript中的!运算符感到困惑。我的理解是!运算符只对布尔值进行操作。但是,在我回答的评论中,有人说它可以对任何东西进行操作,并返回一个布尔值,经过我的测试后,这个说法似乎是正确的。

alert(!undefined); //true
alert(!function(){}); //false
alert(!{}); //false
alert(!null); //true
alert(!()); //crash
alert(!"false"); //false
alert(!false)​;​​​​​​​​​​​​ //true​​​​​​​​​​​​​​​​​​

有人能帮我概括一下 ! 运算符的行为吗?

编辑

更加令人困惑的事情:

​alert( new String() == ""); //true
alert(!""); //true
alert(! new String()); //false

怎么做?


17
欢迎来到 JavaScript。如果你来自一个强类型的世界,那么你现在步入了未知领域。 - Darin Dimitrov
1
JavaScript会将这些类型隐式转换为布尔值。 - helpermethod
1
与此有些相关的是,您可能会对我在stackoverflow上关于js中null和undefined之间差异的问题感兴趣。https://dev59.com/c2w05IYBdhLWcg3w11Mk - Endophage
5个回答

20

!做的就是你想的那样:将true变成false,反之亦然。这种奇怪的行为与Javascript如何将任何东西转换为truefalse有关。

http://11heavens.com/falsy-and-truthy-in-javascript

Like in C(只不过更糟),所有值都可以提升为true或false。你想要搜索的术语是"truthy"和"falsy",或者"truthiness"和"falsiness"。Truthy表示某些东西转换为true,falsy表示某些东西转换为false。除了null、undefined、0、""、NaN和false之外,所有值都是truthy的。
此链接有更多有趣的例子:

http://www.sitepoint.com/javascript-truthy-falsy/

这个网站似乎特别喜欢对这里的有趣行为进行病态处理:

http://wtfjs.com

此外,请注意,==会尽力使事物可比较,而===如果事物不可比较则返回false。Crockford在《JavaScript语言精粹》中建议完全不使用==

谢谢提供链接...但那并没有真正回答我的问题...实际上我想问的是在JavaScript中!运算符是如何定义的。 - hrishikeshp19
2
没错,但你问错了问题。!正是你想的那样,它将true变为false,反之亦然。你看到的奇怪行为更多地与你应用!的事物的真实性有关。 - djechlin
评论是在回答被编辑之前的...新的答案更好 :) 与其他回答一起,它很有帮助。谢谢 :) - hrishikeshp19
http://wtfjs.com 似乎已经无法访问了。我现在非常好奇以前那里的例子是什么 :) - Wilt

8
这并不完全是由于!的函数,而是由于javascript中的真假值。如果您熟悉类型转换,即将变量强制转换为特定类型,则以下内容应该很清楚。 !仅适用于布尔值。因此,在应用!之前,您将其应用于的任何非布尔变量都会首先被强制转换为布尔值。为了与您的示例相关联:
Boolean(undefined) == false 

undefined在JavaScript中有点像null(虽然它们之间有些差异,但这是另一个话题)。布尔值等价于false是有道理的。 undefined不仅表示缺少值,而且还声明你正在尝试使用的变量根本不存在。

Boolean(function(){}) == true

函数在JavaScript中是一种对象。即使它是空的,它仍然具有一些基本属性,这些属性对于函数对象是共同的,因此它的布尔等效值为true。它不是空的,所以它是存在的。

Boolean({}) == true

就像一个空函数一样,{} 定义了一个空对象。然而,它仍然具有 JavaScript 对象的一些共同属性。它只是没有自定义属性。

Boolean(null) == false

就像我提到的undefinednull也类似但又有所不同。它表示值的缺失。

Boolean(()) // error
< p > < code >()< /code >单独使用并没有实际意义,你需要在括号中间加入内容以使其符合语法规则,这与你的真/假问题无关。只有()是语法错误。< /p >
Boolean("false") == true

"false"是一个字符串。仅仅因为它包含了字母f,a,l,s,e,并不意味着它与布尔值false相同。非空字符串是某种东西,因此强制转换为布尔型true。请注意,字符串是一种特殊的对象,空字符串""强制转换为false,但是一个空对象{},如上所述,强制转换为true

Boolean(false) == false

这个应该很清楚了。 false已经是一个布尔型,因此将其转换不会改变其值。它仍然是false

从中可以看出,对每种情况应用!将给您看到的结果。

有关更多信息,请参见javascript类型强制转换的一篇相当不错的文章

更新:

关于您的String问题。 String对象和字符串文字(用引号括起来的内容)之间存在差异。您可以从字符串文本创建String对象,但是文本并不自动成为对象。在javascript中,数字也是如此。JS有一个Number对象,但您经常定义数字文字。 Number的行为与您在String中看到的一致:

alert( new Number() == 0); //true
alert(!0); //true
alert(! new Number()); //false

然而,正如你在评论中敏锐指出的一样:
alert( new String() === ""); //false

由于类型不同,分别为对象和字面量。

通常情况下,Boolean(some_object)将始终评估为true,但根据确切的值,Boolean(some_literal)可能会评估为false。

补充说明

就在本周我自己踩了个坑,所以我认为这是一个有用的信息。在大多数语言中,空数组[]将被强制转换为false。然而,在Javascript中,数组是对象,因此即使是空数组也会被强制转换为true。需要注意的一点是,在js和各种服务器端语言之间切换时,很容易出现错误,例如if(!maybe_empty_array){...},这将永远无法通过,因为maybe_empty_array将始终强制转换为true。相反,您应该执行if(maybe_empty_array.length){...}。如果数组为空,则其长度为0,安全地强制转换为false


+1 感谢您澄清字符串相关的问题...它符合我的新测试,new String() === "" 返回false...所以,我的编辑实际上是无效的。 - hrishikeshp19
@hrishikeshp19 哦,是的,我应该提到 ===。这使得清楚,虽然它们可以被强制转换为相同的值,但类型不同,因此 == 返回 true,但 === 返回 false。 - Endophage
2
请注意,new String() === new String() 也返回 false,因为操作数是两个不同的对象。 - nnnnnn
1
@nnnnnn 好奇的是,new String() == new String() 的结果也是 false。我猜这与 NaN == NaN 的结果为 false 是一致的,但我不确定为什么会这样(也就是说,我理解为什么会得到这个结果,但我不知道是谁认为这是一个合理的实现并将其规范化)。 - Endophage

5

"有人能帮我概括一下!运算符的行为吗?"

当单个操作数可以转换为true时,它返回false;否则返回true。

任何对象(包括“空”对象{}或函数),任何非空字符串和任何非零数字都可以被转换为true。另一方面,null、undefined、空字符串和零都将被转换为false。因此,!运算符返回相反的结果,这就是你在问题中展示的结果。


1
@hrishikeshp19 - 它未被定义,因此它是真的。 - PitaJ
1
@PitaJ - 不,{}是一个对象,任何对象都是真值,所以!{}是假的。 - nnnnnn
如果任何对象都是真值,为什么 ""(与 new String() 相同)是假的? - hrishikeshp19
@PitaJ 不不不..要么你错了,要么我没理解你想说的话...我发现 new String() == "" => true 但是 new String()==="" => false ...所以我的修改并不是一个有效的问题。 - hrishikeshp19
2
在JS中,字符串和字符串对象并不完全相同。(这有点像Java中int和Integer之间的区别。)typeof ""是“string”,而typeof new String()是“object”。这很令人困惑,但字符串是值类型,但当您在它们上调用字符串方法(例如.substr())时,它们会被转换为对象。(类似地,您可以在数字原语上调用Number方法,例如123.123.toFixed(1)返回123.1。) - nnnnnn
显示剩余2条评论

3

如果它的单个操作数可以转换为true,或者它是一个非布尔值,则返回false:

!(x == y)
!"something" 

如果操作数可以转换为false,则返回true。
!(x > y)

0

很难写出比这更通用的解释:

var arr = [0, "", false, null, undefined, NaN];

for(var i = 0; i < 6; i++){
    console.log(!(arr[i]));//always true
}

任何其他值都会产生false

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