JavaScript 会在使用双等号运算符 (==) 时尝试强制类型。规范中的详细信息:sec 11.9.3: Abstract Equality Comparison Algorithm。
示例 1:
console.log( 0 == '0' ); // true
JavaScript 将字符串强制转换为数字 0,因此是 0 == 0。
示例 2:
console.log( 0 == [] ); // true
与数字比较时,空数组的“ToPrimitive”值为零。所以这个减少到0 == 0。
示例 3:
console.log( [] == '0' ); // false
console.log( [] == '' ); // true
虽然第一个看起来与前面的示例非常相似,但两边都不是数字。乍一看,这似乎是一个truthy 比较,但[] 不是八个falsy values 之一。
证明[] 是真的,但'' 是假的:
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
这可能 EITHER 表示数组 (1) 的 长度 是“真实的”,与 '' 比较是“虚假的” ",所以true == false,即false。 OR 它可能表示没有合适的类型转换,即规范中的 case (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
令人惊讶的是,当与非空字符串进行比较时,包含一个数字的数组显然会转换为该数字。然后转到将数字与字符串进行比较的规则,该规则将字符串转换为数字。因此,我们将(0 或 1 或 ..)与(0 或 1 或 ..)进行比较。
这是规范中的歧义吗?不同的实现有区别吗?
测试于 2020 年 10 月 27 日在 https://www.webtoolkitonline.com/javascript-tester.html 在 Windows 10 电脑上的 Chrome 中完成,使用 alert 而不是 console.log。
示例 6:
如果以上所有内容都不能说服您不再使用==,请考虑以下几点:
var a = [];
console.log( a == a ); // true
但是:
console.log( [] == [] ); // false
规范中的 9 条类型转换规则都不适用,所以这是第 10 种情况:它们不是同一个对象,即使它们都没有任何内容。它们是空数组的两个不同实例。
总而言之,这就是为什么使用三重等号通常更安全的原因,它检查类型和相等性。
一个方便的说明(用于测试真实性的案例)如下:
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"));