初级 JavaScript 开发者的常见错误:进阶篇

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

初级 JavaScript 开发者的常见错误:进阶篇



当你已经掌握了 JavaScript 的基本语法,并为浏览器或 Node.js 编写了几个脚本后,似乎最困难的部分已经过去了。但正是在过渡到实际项目(通常在 Node.js 服务器端)的阶段,开发者会遇到一些棘手的错误。这些错误不会立即破坏代码,但会导致难以察觉的 bug、内存泄漏和意外行为。在本文中,我们将分析初级 JavaScript 开发者常犯的 4 个进阶错误,并展示如何避免它们。



1. 对循环中闭包 (Closures in Loops) 的理解不足



这是一个从浏览器 JavaScript 延续到 Node.js 的经典问题。许多人都知道 var 具有函数作用域而非块级作用域,但即使使用 let,如果错误地使用异步回调,也会出现错误。



问题: 你在循环中创建了一个函数数组,并期望每个函数记住它自己的计数器值。但实际上,所有函数都引用了最后一个值。



// ❌ 错误:所有调用都会返回 3const functions = [];for (var i = 0; i < 3; i++) {    functions.push(() => console.log(i));}functions.forEach(fn => fn()); // 3, 3, 3


为什么会这样? 闭包捕获的不是变量 i 的值,而是对变量本身的引用。当函数被调用时,循环已经结束,i 等于 3。



解决方案(针对 Node.js): 使用 let 获得块级作用域,或者通过 IIFE(立即调用函数表达式)创建新的闭包。



// ✅ 使用 let 修复const functions = [];for (let i = 0; i < 3; i++) {    functions.push(() => console.log(i));}functions.forEach(fn => fn()); // 0, 1, 2

// ✅ 使用闭包修复(立即调用函数)for (var i = 0; i < 3; i++) { (function(j) { functions.push(() => console.log(j)); })(i);}


2. 忽视异步:Promise 的“竞态条件”与 this 上下文丢失



Node.js 是一个异步环境。最常见的错误之一是在异步操作完成之前尝试使用其结果,或者在方法内部丢失 this 上下文。



示例 1:Promise 竞态条件 (Race condition)



// ❌ 错误:结果可能是 undefinedlet userData;fetchUserData().then(data => {    userData = data;});console.log(userData); // undefined — 同步代码先执行了


示例 2:回调中丢失 this



class Logger {    constructor(prefix) {        this.prefix = prefix;    }    logLater() {        setTimeout(function() {            console.log(this.prefix); // undefined — this 指向全局对象        }, 100);    }}const logger = new Logger('INFO:');logger.logLater(); // undefined


解决方案: 对于顺序操作始终使用 async/await,并使用箭头函数来保留上下文。



// ✅ 使用 async/await 修复async function getUserData() {    const userData = await fetchUserData();    console.log(userData); // 现在数据肯定存在}

// ✅ 使用箭头函数修复class Logger { constructor(prefix) { this.prefix = prefix; } logLater() { setTimeout(() => { console.log(this.prefix); // INFO: }, 100); }}


3. Promise 链和流 (Streams) 中的错误处理不当



在 Node.js 中,许多操作返回 Promise 或流。初级开发者常常忘记在链的中间或流中处理错误,这会导致“静默”崩溃

博客

书籍推荐