当心,这些 JavaScript 坑让人防不胜防!


JavaScript 作为一门灵活的编程语言,有着许多令人困惑的特性和行为。即使是经验丰富的开发者,有时也会掉入这些”陷阱”中,分享一些我遇到的也踩过的坑。

1. 类型转换的迷惑

JavaScript 的类型转换规则可能会让人摸不着头脑:

console.log([] + []); // 输出:""  
console.log([] + {}); // 输出:"[object Object]"  
console.log({} + []); // 输出:0(在某些浏览器中)  
console.log([] == ![]); // 输出:true  

这些看似不合理的结果,其实都遵循着 JavaScript 的类型转换规则。当进行加法运算时,JavaScript
会优先将操作数转换为原始类型,然后进行运算。

2. 变量提升的陷阱

console.log(a); // 输出:undefined  
var a = 1;  
  
console.log(b); // 报错:ReferenceError  
let b = 2;  

变量提升是 JavaScript 中一个经典的概念。使用 var 声明的变量会被提升到作用域顶部,但初始化不会提升。而 let 和 const
声明的变量存在暂时性死区(TDZ),在声明前访问会抛出错误。

3. this 指向问题

const obj = {  
    name: '小明',  
    sayHi() {  
        setTimeout(function() {  
            console.log('你好,' + this.name);  
        }, 100);  
    }  
};  
  
obj.sayHi(); // 输出:你好,undefined  

在这个例子中,setTimeout 中的回调函数里的 this 指向全局对象(非严格模式下)或 undefined(严格模式下),而不是
obj。解决方案包括:

// 方案1:使用箭头函数  
setTimeout(() => {  
    console.log('你好,' + this.name);  
}, 100);  
  
// 方案2:使用 bind  
setTimeout(function() {  
    console.log('你好,' + this.name);  
}.bind(this), 100);  

4. 闭包陷阱

for (var i = 0; i < 3; i++) {  
    setTimeout(() => {  
        console.log(i);  
    }, 100);  
}  
// 输出:3, 3, 3  

这是一个经典的闭包问题。使用 var 声明的变量 i 是函数作用域的,所有的 setTimeout 回调都共享同一个 i。解决方案:

5. 数值计算精度问题

console.log(0.1 + 0.2); // 输出:0.30000000000000004  
console.log(0.1 + 0.2 === 0.3); // 输出:false  

这是因为 JavaScript 使用 IEEE 754 双精度浮点数来表示数字,某些小数无法被精确表示。解决方案:

6. 数组方法的陷阱

解决方案:

7. Promise 的常见陷阱

正确的做法:

8. 事件监听器的内存泄漏

// 错误示例:可能造成内存泄漏  
function addHandler() {  
    const element = document.getElementById('button');  
    element.addEventListener('click', () => {  
        console.log('Clicked');  
    });  
}  
  
// 正确示例:  
function addHandler() {  
    const element = document.getElementById('button');  
    const handler = () => {  
        console.log('Clicked');  
    };  
    element.addEventListener('click', handler);  
      
    // 清理函数  
    return () => {  
        element.removeEventListener('click', handler);  
    };  
}  

欢迎补充。