javascript为何会存在闭包概念【教程】

12次阅读

闭包是词法作用域、函数作为一等公民和垃圾回收机制共同作用的自然结果;当内部函数引用外部变量并逃出定义作用域执行时形成闭包,否则不构成;常见问题包括循环变量捕获异常和内存泄漏。

javascript为何会存在闭包概念【教程】

闭包不是 javaScript 故意“加”的一个功能,而是词法作用域 + 函数作为一等公民 + 垃圾回收机制三者自然碰撞出的结果——它不靠语法关键字声明,而是在你写嵌套函数并返回/传递时,自动产生

为什么 function 返回另一个 function 就会形成闭包?

  • javascript 在函数定义时就固定了它的词法作用域(即“它写在哪,就认哪的变量”),而不是调用时才查;
  • 当内部函数被返回或赋值给外部变量(比如 const counter = createCounter()),它仍带着对原始定义环境的引用;
  • 引擎发现这个内部函数还在用 count,即使 createCounter 已执行完、本该销毁局部变量count 也不能被回收——否则 counter() 下次调用就会报错或读到 undefined

这背后没有魔法,只是引擎按规则走:只要变量还在被活引用,就得留着

常见误判:不是所有嵌套函数都是闭包

  • inner 定义在 outer 里 ≠ 形成闭包;
  • 关键看它是否 真正引用了外部变量,且该函数 逃出了定义它的作用域去执行
function outer() {   const x = 1;   function inner() {     console.log('没用x,不算闭包'); // 没引用外部变量   }   return inner; }

上面的 inner 不是闭包。而下面这个是:

function outer() {   const x = 1;   return function() { console.log(x); }; // 引用了 x,且被返回出去 }

闭包最常踩的坑:内存泄漏和循环中变量捕获异常

  • for 循环里直接给元素绑事件,用 var 声明的循环变量会被所有闭包共享:

    立即学习Java免费学习笔记(深入)”;

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

    解决方式:

    • 改用 let(块级作用域,每次迭代新建绑定);
    • 或用立即执行函数包裹:(function(i) { setTimeout(() => console.log(i), 100); })(i)
    • 或用 foreach 替代 for
  • 长期持有 dom 引用的闭包(比如事件监听器里存了整个节点),又没手动 removeEventListener,变量就一直无法释放。

闭包本身无害,问题出在「引用没及时断」——它像一根看不见的线,把本该消失的变量拽在内存里。写的时候多问一句:这个变量,我之后真还需要吗?

text=ZqhQzanResources