学习前提
理解变量、条件与循环,能阅读函数调用表达式。
本课完成后你能做什么
把重复逻辑提取为可测试函数,并用闭包保存彼此隔离的状态。
先理解机制
参数是输入,return 是输出;没有执行 return 时返回 undefined。尽量把计算函数设计成相同输入产生相同结果,DOM修改和存储等副作用留在边界。这样可以直接用输入输出验证规则,而不必每次点击页面。
let 和 const 具有块作用域,函数能访问定义位置的外层变量,这叫词法作用域。闭包保留的是对环境的访问,不是变量在创建时的冻结快照。每次调用工厂函数会产生自己的局部环境,适合组件计数器。
箭头函数捕获外层 this,普通函数的 this 由调用方式影响;不要仅为了写短而随意替换对象方法。异步回调中的错误不会被已经结束的同步 try 包住,异步错误应在 await 周围处理。
可运行示例
function makeCounter(start = 0) {
let value = start;
return {
increment() { value += 1; return value; },
read() { return value; }
};
}
const a = makeCounter();
const b = makeCounter(10);
console.log(a.increment(), a.increment(), b.read());
推演与验证
输出1、2、10。再次调用 makeCounter 得到新环境。外部无法直接读取局部 value,但返回方法可以。把 increment 改为只更新不 return,观察输出变成 undefined,理解状态变化与返回值的区别。
常见错误与边界
闭包可能长期保留较大的对象;不再需要的事件监听和定时器应解除。递归需要终止条件;深递归不适合无界数据。不要依赖函数声明提升来掩盖混乱的初始化顺序。
动手练习
给计数器增加 reset 方法,使其恢复创建时的 start;验证a重置不会影响b。
参考解法与理由
start 也属于该次调用的词法环境。reset 修改当前实例的 value,返回更新值可以让调用者立即渲染。
// Add this method to the returned object:
// reset() { value = start; return value; }