跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

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免费学习笔记(深入) ”; Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的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
,变量就一直无法释放。 闭包本身无害,问题出在「引用没及时断」——它像一根看不见的线,把本该消失的变量拽在内存里。写的时候多问一句:这个变量,我之后真还需要吗?

相关文章