一、== 与 === 的类型隐式转换
console.log(0 == "0"); // true
console.log(0 === "0"); // false
原因解析:
- == 会进行类型转换后比较值
- 字符串 "0" 转换为数字时变成 0
- === 严格比较类型和值,0 是数字,"0" 是字符串
常见陷阱:
console.log(false == 0); // true
console.log(null == undefined); // true
console.log([] == false); // true(空数组转换为数字0)
避坑指南:
- 永远使用 === 进行严格比较
- 特殊场景需要转换时,显式转换:
Number("0")
二、数组和对象的引用陷阱
const arr = [1, 2];
arr.push(3); // 成功添加元素
console.log(arr); // [1, 2, 3]
const obj = { name: "Tom" };
obj.age = 20; // 成功添加属性
console.log(obj); // { name: "Tom", age: 20 }
本质区别:
- const 冻结的是变量引用地址
- 数组 / 对象属于引用类型,修改内容不改变地址
- 原始类型(string/number 等)修改会改变地址
深度冻结方法:
const safeArr = Object.freeze([1, 2]);
safeArr.push(3); // 虽然语法允许,但实际不会生效(严格模式会报错)
// 深冻结对象
const deepFreeze = (obj) => {
Object.freeze(obj);
Object.values(obj).forEach(value => {
if (typeof value === 'object' && value !== null) deepFreeze(value);
});
};
三、NaN 的奇怪特性
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true
console.log(isNaN("豆包")); // true(非数字字符串也返回true)
正确判断方法:
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("豆包")); // false(不会进行类型转换)
NaN 的生成场景:
console.log(0 / 0); // NaN
console.log(parseInt("abc")); // NaN
console.log(Math.sqrt(-1)); // NaN
四、最佳实践建议
- 比较操作:始终使用 === 替代 ==
- 常量声明:用 const 声明数组 / 对象时,配合 Object.freeze
- 类型检查:使用 typeof/instanceof/Array.isArray 等工具
- 数值判断:优先使用 Number.isNaN () 替代传统 isNaN ()
五、总结
问题类型 | 现象描述 | 本质原因 | 解决方案 |
---|---|---|---|
类型转换 | 0 == "0" 为 true | == 会自动转换类型 | 使用 === 严格比较 |
引用类型修改 | const 数组仍能添加元素 | const 只冻结引用地址 | Object.freeze 或深拷贝 |
NaN 比较 | NaN === NaN 为 false | NaN 不等于任何值,包括自己 | 使用 Number.isNaN () 判断 |
这些 JavaScript 的常见陷阱往往隐藏在细微的类型差异和引用机制中。通过理解它们的本质原理,我们可以写出更健壮的代码。记住:显式永远比隐式安全,在关键逻辑处添加类型检查能有效减少意外错误。