为什么 "0" == [] 是 false?

28

console.log( 0 == '0' );     // true
console.log( 0 == [] );     // true 
console.log( [] == '0' );    // false

为什么JavaScript会这样评估表达式?


3
数字0是假值,字符串"0"不是。 - Jamiec
因为 true('0')不等于 false([])。 - user3114072
1
Boolean([]) returns true , not false - LiranC
6
由于相同的原因,[] == false![] == false。¯\(ツ) - Siguza
1
  1. 在SO上询问有关JavaScript转换的问题。
  2. 获利。
- ghord
显示剩余7条评论
4个回答

36

当使用双等号操作符(==)时,JavaScript会尝试强制类型转换。具体细节请参见规范:第11.9.3节:抽象相等比较算法

示例1:

console.log( 0 == '0' );     // true

JavaScript将字符串强制转换为数字0,因此0 == 0

示例2:

console.log( 0 == [] ); // true

一个空数组的 "ToPrimitive" 值是零,当与数字进行比较时。 因此,这个表达式简化为 0 == 0
 console.log( [] == '0' ); // false
 console.log( [] == '' ); // true

第一个看起来与先前的示例非常相似,但两侧都不是数字。乍一看,这似乎是一种真值比较,但是[]并不是八个falsy之一。


演示了[]为真值,但''为假值:

 console.log( [] ? true : false ); // true
 console.log( '' ? true : false ); // false

在任何理智的语言中,以上两个语句应该意味着[] == ''应该是false。但正如我们之前所看到的,在JavaScript中并非如此!令人费解的是,使用==时,[]会转换为false:
 console.log( [] == true ); // false
 console.log( [] == false ); // true

结论:两个值都被转换为布尔值,但不是按照“真/假”的规则(这将把 [] 转换为 true,因为它不是八个假值之一)。 相反,使用 == 时,[] 转换为 false
 console.log( [] == '0' ); // `false == true`, so false
 console.log( [] == '' ); // `false == false`, so true

示例 4:

 console.log( [0] == '' ); // false
 console.log( [1] == '' ); // false

这可能意味着数组的长度(1)是“真值”,与“falsy”的''进行比较,所以true == false,即false。或者它可能表示没有适当的类型转换,这是规范中的情况(10),因此为false。但请注意示例5,它似乎不符合任何一种可能性。

例子5:

 console.log( [0] == '0' ); // true
 console.log( [0] == '1' ); // false
 console.log( [1] == '1' ); // true
 console.log( [1] == '0' ); // false
 console.log( [2] == '2' ); // true
 console.log( [1] == '2' ); // false

当将只包含一个数字的数组与非空字符串进行比较时,令人惊讶的是,它会被转换为该数字。然后根据比较数字和字符串的规则,将字符串转换为数字。因此,我们在将(01或..)与(01或..)进行比较。
这是否是规范中的歧义?不同的实现之间有所不同吗?
在2020年10月27日于Windows 10上使用Chrome,在alert而不是console.log中进行的测试,网址为https://www.webtoolkitonline.com/javascript-tester.html

示例6:

如果以上所有内容都没有使您坚决不再使用==,请考虑以下情况:

var a = [];
console.log( a == a ); // true

但是:

console.log( [] == [] ); // false

规范中的9种类型转换规则均不适用,因此这是第10种情况:尽管它们都没有任何内容,但它们不是相同的对象。 它们是空数组的两个不同实例。


总的来说,使用三等号进行类型和相等性检查通常更安全。

A handy illustration (for the cases that test truthiness) below:

function truthyOrFalsy(val) {
    return val ? "Truthy" : "Falsy";
}

console.log("empty array:", truthyOrFalsy([]));
console.log("number zero:", truthyOrFalsy(0));
console.log("string with a zero character:", truthyOrFalsy("0"));


在哪里可以阅读关于这个的内容?关于这种转换是如何进行的? - TheChetan
2
@TheChetan:我的建议是不要去学习它,而是遵循道格拉斯·克罗克福德的建议,始终使用“===”来避免经常处理这种古怪的行为。 - Jack Aidley
3
“both sides are falsey ... one is falsey the other is not” 没有,JavaScript 中的所有列表都是真值(truthy),即使是空列表。因此,假值与其并没有太大关系。 - Arthur Tacca
6
三个例子都稍微或非常具有误导性: 1)两个操作数都被转换为数字,正如您可以看到的16 == "0x10"NaN != "NaN"。 2)真值/伪值不相关;事实上,[] 真值。两者再次被转换为数字,您可以再次用16 == ["0x10"]来查看。 3)再次真值/伪值不相关。两者都被转换为字符串,正如您可以看到的[1,2] == '1,2';空数组被转换为空字符串,这与只包含一个 0 的字符串不相等。 - ETHproductions
我个人认为前两个例子现在好多了。第三个仍需要一些工作:实际上JavaScript可以将它们转换为相同的类型,即字符串。 - ETHproductions
显示剩余7条评论

7
/*
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
*/
console.log( 0 == '0');

/*
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
*/
console.log( 0 == [] );

/*
If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
*/
console.log( [] == '0');

source: http://es5.github.io/#x11.9.3


5
Truthy和Falsy 除了类型外,每个值还具有固有的布尔值,通常称为truthy或falsy。一些规则有点奇怪,因此在调试JavaScript应用程序时,理解这些概念和对比效果是有帮助的。
以下值始终为falsy:
- false - 0(零) - ''或""(空字符串) - null - undefined - NaN(例如1/0的结果)
其他所有值都为truthy。其中包括:
- '0'(包含单个零的字符串) - 'false'(包含文本“false”的字符串) - [](空数组) - {}(空对象) - function(){}(“空”函数)
使用==松散相等性比较truthy和falsy值时可能会发生意外情况:
请参见松散相等性比较表格

Table for loose equality comparison with ==


1
在JS中:[] != []和{} != {} - ziv

0
JavaScript使用类型转换(Type Conversion)来将任何值强制转换为布尔值,以满足需要的上下文环境,例如条件语句和循环语句。
在第一个情况下,...
console.log( 0 == '0'); 

JavaScript使用强制转换将两个值转换为数字并进行比较。现在0 == 0,所以返回true。

在第二种情况下

console.log( 0 == [] );

两者都是假值(假值是指在布尔上下文中评估时转换为false的值)。因此,现在比较false == false,返回true值。

在第三种情况下

console.log( [] == '0'); 

[] 是假值而 '0' 是字符串,JS 无法强制将它们转换为可比较的类型。因此返回 false。


“例如条件语句和循环语句” — 这既不是条件语句也不是循环语句,而是等于运算符。第一个情况将把 '0' 转换成数字而不是字符串。第二种情况将把数组转换为数字。第三种情况将把数组转换为字符串并进行比较。 https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 - Quentin
https://developer.mozilla.org/en-US/docs/Glossary/Falsy - Sandip Kumar
那份文档说它适用于布尔上下文,而“==”不是布尔上下文。 - Quentin

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