【易错求解】为什么 [] == "" && [] == 0 && "" == 0 && [] != [] ?

思否 问答 👍 2 含 AI 优化版

问题

【易错求解】为什么 [] == "" && [] == 0 && "" == 0 && [] != [] ?

在 SegmentFault 查看原问题 →

由大模型辅助整理,保留原意,优化结构与可读性。

问题概述

JavaScript 中存在一组反直觉的宽松相等(==)比较结果:[] == ""[] == 0"" == 0 均为 true,但 [] != [] 也为 true(即两个空数组并不相等)。希望理解背后的类型转换规则。

涉及技术(如有)

  • JavaScript 抽象相等比较(==)的类型转换规则
  • 引用类型到基本类型的转换(Symbol.toPrimitivevalueOftoString
  • Proxy 用于观察对象属性访问

期望结果

理解 == 比较时的隐式类型转换顺序,并明确为什么工作中应尽量使用 ===

回答

原始回答

2023-03-11 如果是工作中,大概率不需要为此劳心费神,一般我们只需要使用 === 强等于做类型匹配,加上 TypeScript 大概率不会出现这种怪异的代码。如果是面试的话,那么我们需要掌握几个点是否有显式类型转换,这里需要注意一下表达式的运算优先级当做计算的时候,可以记住一个顺序。会把引用类型变成基本类型。Symbol(Symbol.toPrimitive)valueOftoStringconsole.log(34 == '034')

console.log(52 == '0x34')a = new Proxy([],{

get(obj, key){

console.log('proxy', 'get', '1', key, obj[key] instanceof Function?objkey:obj[key])

return obj[key]

}

});

b = new Proxy([],{

get(obj, key){

console.log('proxy', 'get', '2', key, obj[key] instanceof Function?objkey:obj[key])

return obj[key]

}

});

// performance

console.group(a == !b)

console.log(a == !b)

console.groupEnd(a == !b)

console.group(1 + a)

console.log(1 + a)

console.groupEnd(1 + a)

console.group('1' + a)

console.log('1' + a)

console.groupEnd('1' + a)

console.group(a + 1)

console.log(a + 1)

console.groupEnd(a + 1)

console.group(a + '1')

console.log(a + '1')

console.groupEnd(a + '1')MDN - JavaScript 数据类型和数据结构本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。

AI 优化 · 回答整理

解答思路

这几个比较结果都是 == 隐式类型转换规则导致的:只要比较的两边类型不同,引擎会按固定顺序把一方(或双方)转换成基本类型再比较。而 [] != [] 比较的是两个不同的对象引用,永远不相等(无论内容是否相同)。

示例代码(如有代码)

console.log(34 == '034');   // true,字符串被转成数字比较
console.log(52 == '0x34');  // true,'0x34' 会被解析为十六进制数字 52

// 用 Proxy 观察对象转基本类型时的属性访问顺序
const a = new Proxy([], {
  get(obj, key) {
    console.log('proxy', 'get', '1', key, obj[key] instanceof Function ? obj[key]() : obj[key]);
    return obj[key];
  },
});
const b = new Proxy([], {
  get(obj, key) {
    console.log('proxy', 'get', '2', key, obj[key] instanceof Function ? obj[key]() : obj[key]);
    return obj[key];
  },
});

console.group('a == !b');
console.log(a == !b);
console.groupEnd('a == !b');

console.group('1 + a');
console.log(1 + a);
console.groupEnd('1 + a');

console.group("'1' + a");
console.log('1' + a);
console.groupEnd("'1' + a");

console.group('a + 1');
console.log(a + 1);
console.groupEnd('a + 1');

console.group("a + '1'");
console.log(a + '1');
console.groupEnd("a + '1'");

详细说明

  • 如果比较双方类型相同(比如都是对象引用),===== 行为一致,[] != [] 比较的是两个不同数组对象的引用,因此为 true(不相等)。
  • 如果类型不同,会触发类型转换:对象会先尝试 Symbol.toPrimitive,没有的话依次调用 valueOftoString 转成基本类型;[] 转成基本类型后是空字符串 "";再和 0 比较时,字符串又会被转成数字 0。这样就能推出 [] == "" == 0 成立的链条。
  • 表达式的运算符优先级也需要注意,混合使用 ==+! 等操作符时,转换顺序会影响结果,遇到不确定的情况建议加括号或直接打印中间结果验证。
  • 日常业务代码中,建议始终使用 === 做严格类型比较,配合 TypeScript 静态类型检查,基本可以避免这类隐式转换带来的怪异行为。
  • 延伸阅读:MDN - JavaScript 数据类型和数据结构

小结

这几个等式的根源是 == 的隐式类型转换规则(对象 → 基本类型 → 统一类型再比较),而 [] != [] 属于对象引用比较,与前面的转换规则无关。实际开发中优先使用 === + TypeScript,能从根本上规避此类问题,这类题目更适合作为面试考察类型转换规则理解程度的题目。

由大模型辅助整理,保留原意,补充结构与代码格式。

回答转载自 SegmentFault

评论

评论功能即将开放。你也可以通过 邮件GitHub Issue 反馈。