JavaScript中===严格相等的对象比较问题及语言设计疑问
嘿,这个问题问到点子上了,我来给你拆解清楚这几个核心点:
为什么值类型用
===能匹配,引用类型不行? JavaScript里的===(严格相等运算符)的行为是分类型的:
- 对于值类型(字符串、数字、布尔值、null、undefined),它直接比较的是变量存储的实际值——只要值一样,结果就是
true,这也是你测试字符串数组时符合预期的原因。 - 对于引用类型(对象、数组、函数等),变量存储的其实是指向内存中对象实例的地址指针。
===比较的就是这个指针:哪怕两个对象的内容完全一致,只要它们是内存里的两个独立实例,指针就不一样,结果自然是false。
给你举个直观的例子:
// 值类型:相同值就相等 const str1 = "apple"; const str2 = "apple"; console.log(str1 === str2); // 输出 true // 引用类型:内容相同但内存地址不同,所以不等 const obj1 = { fruit: "apple" }; const obj2 = { fruit: "apple" }; console.log(obj1 === obj2); // 输出 false
回到你的indicesOf方法:当你在对象数组里用===匹配时,其实是在找和传入对象内存地址完全相同的元素,而不是内容相同的元素,所以才会匹配失败。
为什么JavaScript没有内置的对象深度比较运算符?
这个问题涉及到JavaScript的设计哲学和实际工程考量,主要有这几个原因:
- 性能成本高:深度比较需要递归遍历对象的所有嵌套属性,要是对象很大或者嵌套层级深,会非常耗时。JavaScript作为一门注重运行效率的语言,不会把这种“重量级”操作内置成运算符——毕竟大部分场景下,开发者用不到深度比较,内置反而会带来不必要的性能负担。
- 规则歧义多:深度比较的“相等”标准很难统一。比如:
- 要不要考虑原型链上的属性?
- 遇到循环引用的对象(比如
obj.self = obj)怎么处理? - 日期对象和对应的字符串(比如
new Date("2024-05-20")和"2024-05-20")算不算相等?
这些问题没有标准答案,内置运算符反而会限制开发者的自定义需求。
- 轻量化设计:JavaScript的核心设计思路是“最小核心+社区扩展”——语言本身只提供最基础、最通用的功能,复杂逻辑交给第三方库(比如Lodash的
_.isEqual)或者开发者自己实现,这样能保持语言本身的轻量化和灵活性。
未来会不会加入内置的深度比较功能?
目前TC39(JavaScript的标准化委员会)有几个相关的提案正在推进,但都还处于早期阶段:
- Record & Tuple提案:这个提案引入了不可变的引用类型,这类类型的相等性是基于内容的。比如:
不过这个提案还没进入正式标准,需要更多的讨论和验证。// Record是不可变对象,内容相同就相等 const rec1 = #{ fruit: "apple" }; const rec2 = #{ fruit: "apple" }; console.log(rec1 === rec2); // 输出 true // Tuple是不可变数组,同理 const tup1 = #[1, 2, 3]; const tup2 = #[1, 2, 3]; console.log(tup1 === tup2); // 输出 true - 内置深度比较方法:也有提案讨论过加入类似
Object.isDeepEqual()这样的内置函数,但目前还没有明确的落地时间表。
给你的临时解决方案
如果需要让你的indicesOf方法支持对象数组的内容匹配,可以自己实现一个简单的深度比较函数,替换掉===。比如这个基础版本:
function deepEqual(a, b) { // 先处理值类型和null/undefined的情况 if (a === b) return true; // 排除非对象/数组的情况 if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) { return false; } // 比较属性数量是否一致 const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; // 递归比较每个属性 for (const key of keysA) { if (!keysB.includes(key) || !deepEqual(a[key], b[key])) { return false; } } return true; }
把这个函数用到你的indicesOf里,就能匹配内容相同的对象了。
内容的提问来源于stack exchange,提问作者Rick Riggs
相关产品推荐
相关产品推荐

