重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
本篇内容主要讲解“JavaScript中“闭包”的含义和作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript中“闭包”的含义和作用”吧!
创新互联专业为企业提供太子河网站建设、太子河做网站、太子河网站设计、太子河网站制作等企业网站建设、网页设计与制作、太子河企业网站模板建站服务,十余年太子河做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
在JavaScript中,根据词法作用域的规则,内部函数总是可以访问其外部函数声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,就把这些变量的集合称为闭包。
在一个函数中嵌套另一个函数或者将一个匿名函数作为值传入另一个函数中。
// 函数fun1中嵌套了fun2,fun2作为参数返回,外部调用时仍能打印val1,构成闭包 function fun1() { const val1 = 10; function fun2() { console.log(val1); } return fun2; } function fun3() { const val2 = 20; // 定时器中的为一个匿名函数,其作为参数传入了,函数fun3执行完毕之后,1s钟后才会执行定时器函数,但此时还能打印val2,构成闭包 setTimeout(function() { console.log(val2); }, 1000); }
根据下面的函数来看看闭包的整个执行流程
function main() { const val1 = 20; var val2 = 2 function valResult() { return val1 * val2; } return valResult; } var result = main(); console.log(result()); // 40
上图中展示了各个时期的调用栈,需要重点关注以下几点:
鸿蒙官方战略合作共建——HarmonyOS技术社区
当main函数执行完毕后,main函数的执行上下文从栈顶弹出;
返回的方法(valResult)中调用了main函数中的val1和val2变量,这两个变量就会打包成closure闭包,加到[[scopes]];
调用返回的方法时,作用域链为:result函数作用域——Closure(main)——全局作用域
优点
(1)可以重复使用变量,并且不会造成变量污染;
(2)可以用来定义私有属性和私有方法
缺点
(1)会产生不销毁的上下文,导致栈/堆内存消耗过大
(2)会造成内存泄露。
扩展:闭包是怎么回收的?
鸿蒙官方战略合作共建——HarmonyOS技术社区
如果闭包引入的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄露;
如果引用闭包的函数是一个局部变量,等函数销毁后,在下次JavaScript引擎执行垃圾回收时,判断闭包内容已经不再被使用,则js引擎的垃圾回收器就会进行回收。
闭包用途主要有以下两个:
创建私有变量
function MyName(name) { return { getName() { return name; } } } const myName = MyName('lili'); // 只能通过getName访问对应的名字,别的方式访问不到 console.log(myName.getName()); // lili
作为回调函数。当把函数作为值传递到某处,并在某个时刻进行回调的时候就会创建一个闭包。例如定时器、DOM事件监听器、Ajax请求。
function fun(name) { setTimeout(() => { console.log(name); }, 1000); } fun('linlin');
多个子函数的[[scope]]都是同时指向父级,是完全共享的。因此当父级的变量对象被修改时,所有子函数都受到影响。
for (var i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
上述代码本意是输出1、2、3、4,但结果却是四个5,为了解决该问题,主要有三种办法。
变量可以通过 函数参数的形式 传入,避免使用默认的[[scope]]向上查找
for (var i = 1; i < 5; i++) { (function(i) { setTimeout(() => console.log(i), 1000); })(i); }
使用setTimeout包裹,通过第三个参数传入。(注:setTimeout后面可以有多个参数,从第三个参数开始其就作为回掉函数的附加参数)
for (var i = 1; i < 5; i++) { setTimeout(value => console.log(value), 1000, i); }
使用 块级作用域,让变量成为自己上下文的属性,避免共享
for (let i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); }
到此,相信大家对“JavaScript中“闭包”的含义和作用”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!