四条主线:作用域决定变量可见性,闭包使变量持久化,this由调用方式决定且箭头函数不绑定自身this,柯里化利用闭包实现参数分步传入。

直接抓住四条主线:作用域决定变量在哪能用,闭包让变量“赖着不走”,this是函数执行时的上下文对象,箭头函数则不绑定自己的this,而柯里化是靠闭包把多参函数“拆成单参接力赛”。学得快的关键不是背定义,而是看清它们怎么相互咬合。
作用域:变量的“地盘划分”规则
JS 有三类作用域:全局、函数(ES5)、块级(let/const)。变量查找永远遵循词法作用域——看函数在代码里写在哪一层,就固定从哪一层往上找,跟函数在哪调用无关。比如嵌套函数里访问外层变量,引擎不是看“谁调了我”,而是看“我定义时外面包着谁”。
注意两个易错点:
- var 声明会变量提升,但 let/const 不会——只提升声明,不初始化(暂时性死区)
- for 循环中用 var 定义 i,所有回调共享同一个 i;换成 let 就每个迭代有自己的块级作用域
闭包:函数 + 它“记住”的外部变量
闭包不是某种特殊函数,而是函数与其词法环境的组合体。形成闭包只需三个条件:函数嵌套、内部函数引用外部变量、外部函数返回内部函数(或将其传出作用域)。
它真正解决的问题是:
- 封装私有数据(如计数器中的 count 变量无法被外部直接修改)
- 延长变量生命周期(外部函数执行完,变量仍保留在内存中)
- 为柯里化、防抖、模块化提供基础机制
⚠️ 注意:闭包本身不导致内存泄漏,但若引用了大对象又长期不释放,才可能堆积内存。用完及时置 null 或脱离引用即可。
this 绑定:五条规则按优先级排队
this 不由函数定义位置决定,而由调用方式决定。优先级从高到低是:
- new 调用 → this 指向新创建的实例
- call/apply/bind 显式绑定 → this 被强制指定
- 对象方法调用(obj.fn())→ this 指向 obj
- 普通函数调用(fn())→ 非严格模式下指向 window/global,严格模式下为 undefined
- 箭头函数 → 没有 this,沿外层作用域继承(本质是把它当普通变量处理)
记一个典型反例:setInterval(obj.method, 1000) 中 method 的 this 是 window,因为 setInterval 内部是普通调用;而 setInterval(() => obj.method(), 1000) 或 setInterval(obj.method.bind(obj), 1000) 才能保持 this 指向 obj。
箭头函数与柯里化:一对默契搭档
箭头函数没有自己的 this、arguments、prototype,也不能用 new。它的 this 是词法绑定的——写在哪层作用域,就继承哪层的 this。这使它天然适合写回调,避免手动 bind。
柯里化本质是利用闭包缓存参数,逐步收集成完整参数列表再执行。例如:
const add = (a) => (b) => (c) => a + b + c;const add2 = add(2);
const add2And3 = add2(3);
add2And3(4); // 9
每一步返回的新函数都闭包了前面传入的参数。现代实现常用递归+剩余参数(...args),配合 fn.length 判断是否收齐参数。











