JavaScript中闭包的详解
发布时间 - 2026-01-11 00:28:24 点击率:次闭包是什么

在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
是不是看完这个定义感觉更加懵逼了?别急,我们来分析一下。
- 闭包是一个函数
- 闭包可以使用在它外面定义的变量
- 闭包存在定义该变量的作用域中
好像有点清晰了,但是使用在它外面定义的变量是什么意思,我们先来看看变量作用域。
变量作用域
变量可分为全局变量和局部变量。全局变量的作用域就是全局性的,在 js 的任何地方都可以使用全局变量。在函数中使用 var 关键字声明变量,这时的变量即是局部变量,它的作用域只在声明该变量的函数内,在函数外面是访问不到该变量的。
var func = function(){
var a = 'linxin';
console.log(a); // linxin
}
func();
console.log(a); // Uncaught ReferenceError: a is not defined
作用域相对比较简单,我们不多讲,来看看跟闭包关系比较大的变量生存周期。
变量生存周期
全局变量,生命周期是永久的。局部变量,当定义该变量的函数调用结束时,该变量就会被垃圾回收机制回收而销毁。再次调用该函数时又会重新定义了一个新变量。
var func = function(){
var a = 'linxin';
console.log(a);
}
func();
a 为局部变量,在 func 调用完之后,a 就会被销毁了。
var func = function(){
var a = 'linxin';
var func1 = function(){
a += ' a';
console.log(a);
}
return func1;
}
var func2 = func();
func2(); // linxin a
func2(); // linxin a a
func2(); // linxin a a a
可以看出,在第一次调用完 func2 之后,func 中的变量 a 变成 'linxin a',而没有被销毁。因为此时 func1 形成了一个闭包,导致了 a 的生命周期延续了。
这下子闭包就比较明朗了。
- 闭包是一个函数,比如上面的 func1 函数
- 闭包使用其他函数定义的变量,使其不被销毁。比如上面 func1 调用了变量 a
- 闭包存在定义该变量的作用域中,变量 a 存在 func 的作用域中,那么 func1 也必然存在这个作用域中。
现在可以说,满足这三个条件的就是闭包了。
下面我们通过一个简单而又经典的例子来进一步熟悉闭包。
for (var i = 0; i < 4; i++) {
setTimeout(function () {
console.log(i)
}, 0)
}
我们可能会简单的以为控制台会打印出 0 1 2 3,可事实却打印出了 4 4 4 4,这又是为什么呢?我们发现,setTimeout 函数时异步的,等到函数执行时,for循环已经结束了,此时的 i 的值为 4,所以 function() { console.log(i) } 去找变量 i,只能拿到 4。
我们想起上一个例子中,闭包使 a 变量的值被保存起来了,那么这里我们也可以用闭包把 0 1 2 3 保存起来。
for (var i = 0; i < 4; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, 0)
})(i)
}
当 i=0 时,把 0 作为参数传进匿名函数中,此时 function(i){} 此匿名函数中的 i 的值为 0,等到 setTimeout 执行时顺着外层去找 i,这时就能拿到 0。如此循环,就能拿到想要的 0 1 2 3。
内存管理
在闭包中调用局部变量,会导致这个局部变量无法及时被销毁,相当于全局变量一样会一直占用着内存。如果需要回收这些变量占用的内存,可以手动将变量设置为null。
然而在使用闭包的过程中,比较容易形成 JavaScript 对象和 DOM 对象的循环引用,就有可能造成内存泄露。这是因为浏览器的垃圾回收机制中,如果两个对象之间形成了循环引用,那么它们都无法被回收。
function func() {
var test = document.getElementById('test');
test.onclick = function () {
console.log('hello world');
}
}
在上面例子中,func 函数中用匿名函数创建了一个闭包。变量 test 是 JavaScript 对象,引用了 id 为 test 的 DOM 对象,DOM 对象的 onclick 属性又引用了闭包,而闭包又可以调用 test ,因而形成了循环引用,导致两个对象都无法被回收。要解决这个问题,只需要把循环引用中的变量设为 null 即可。
function func() {
var test = document.getElementById('test');
test.onclick = function () {
console.log('hello world');
}
test = null;
}
如果在 func 函数中不使用匿名函数创建闭包,而是通过引用一个外部函数,也不会出现循环引用的问题。
function func() {
var test = document.getElementById('test');
test.onclick = funcTest;
}
function funcTest(){
console.log('hello world');
}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
# js
# 闭包
# 详解JavaScript闭包问题
# 关于Javascript闭包与应用的详解
# 详解JavaScript作用域 闭包
# 详解JavaScript匿名函数和闭包
# JavaScript闭包和回调详解
# JavaScript闭包详解
# 是一个
# 全局变量
# 形成了
# 可以使用
# 就会
# 就能
# 去找
# 不被
# 值为
# 让人
# 出了
# 很难
# 就有
# 可以说
# 可以用
# 不多
# 只需
# 设为
# 要把
# 看完
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
nodejs redis 发布订阅机制封装实现方法及实例代码
如何用景安虚拟主机手机版绑定域名建站?
简历在线制作网站免费版,如何创建个人简历?
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
南京网站制作费用,南京远驱官方网站?
历史网站制作软件,华为如何找回被删除的网站?
如何在 Pandas 中基于一列条件计算另一列的分组均值
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置
Java类加载基本过程详细介绍
教学论文网站制作软件有哪些,写论文用什么软件
?
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化
如何在云主机上快速搭建多站点网站?
Laravel如何使用Gate和Policy进行授权?(权限控制)
详解阿里云nginx服务器多站点的配置
如何用搬瓦工VPS快速搭建个人网站?
html文件怎么打开证书错误_https协议的html打开提示不安全【指南】
香港服务器如何优化才能显著提升网站加载速度?
Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践
如何在腾讯云服务器上快速搭建个人网站?
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
如何在香港免费服务器上快速搭建网站?
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程
太平洋网站制作公司,网络用语太平洋是什么意思?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
怎么用AI帮你设计一套个性化的手机App图标?
如何确认建站备案号应放置的具体位置?
如何用免费手机建站系统零基础打造专业网站?
Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程
Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】
Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?
Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】
浅谈javascript alert和confirm的美化
如何在Windows环境下新建FTP站点并设置权限?
如何快速完成中国万网建站详细流程?
Laravel如何记录自定义日志?(Log频道配置)
Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置
Android中AutoCompleteTextView自动提示
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
高性能网站服务器部署指南:稳定运行与安全配置优化方案
html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】
HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】
Android 常见的图片加载框架详细介绍

