闭包是JS"会用"和"懂原理"的分水岭,几乎每场JS面试都要考。
闭包:函数+它定义时的词法环境。"关闭"了那个环境里的变量。
作用域链:查找变量时JS从最内层往外沿着词法环境链一路找。
经典题:`for (var i=0; i<3; i++) setTimeout(()=>console.log(i))`输出3,3,3——var是函数作用域,三个回调共享同一个i。
修:改成let(块作用域,每轮新binding)或用IIFE捕获当前值。
内存:闭包持引用;闭包活得比作用域久,被捕获的变量就回收不掉。常见泄漏源。
闭包=函数+它出生那个作用域,即便外层函数返回了也还能访问那些变量。经典题:var循环+setTimeout回调。var是函数作用域,三个回调引用同一个i,执行时i已经是3,所以3,3,3。换成let每轮都是新binding,就是0,1,2。我故意用这个模式做数据私有——只暴露操作私有状态的方法,不用挂在对象上。内存注脚:DOM节点被闭包引用又活得比节点久就是经典泄漏,addEventListener最常见。
ES6模块免费给你私有性——纯为隐私用闭包现在用得少,但库里还常见。
DevTools→Memory→Heap snapshot里闭包是单独分类——排泄漏利器。
即答侠整理了闭包TOP5坑,一看形状就能认出来。
严格说是——每个函数都捕获词法环境。实际只有外层作用域已经消失时我们才叫"闭包"。
作用域语义一样。差别在`this`绑定(箭头继承,普通自带)和arguments/new.target。