闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。 闭包是 JavaScript 语言的一大特点,主要应用闭包场合主要是为了:设计私有的方法和变量。
闭包的几种表现形式
- 返回一个函数
- 作为函数参数传递
- 回调函数
- 非典型闭包IIFE(立即执行函数表达式)
返回一个函数:这种形式的闭包在JavaScript
的代码编写中,是非常常见的一种方式。
var a = 1; function foo(){ var a = 2; // 这就是闭包 return function(){ console.log(a); } } var bar = foo(); // 输出2,而不是1 bar();
作为函数参数传递:无论通过何种手段将内部函数传递到它所在词法作用域之外,它都会持有对原始作用域的引用,无论在何处执行这个函数,都会产生闭包。
var a = 1; function foo(){ var a = 2; function baz(){ console.log(a); } bar(baz); } function bar(fn){ // 这就是闭包 fn(); } // 输出2,而不是1 foo();
回调函数:在定时器、事件监听、Ajax请求、跨窗口通信、Web Workers或者任何异步中,只要使用了回调函数,实际上就是在使用闭包。
// 定时器 setTimeout(function timeHandler(){ console.log('timer'); },100) // 事件监听 $('#container').click(function(){ console.log('DOM Listener'); })
IIFE:IIFE(立即执行函数表达式)并不是一个典型的闭包,但它确实创建了一个闭包。
var a = 2; (function IIFE(){ // 输出2 console.log(a); })();
经典循环和闭包面试题
以下代码运行结果是什么,如何改进?
for(var i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i) }, i*1000) }
代码分析:
for
循环创建了5个定时器,并且定时器是在循环结束后才开始执行for
循环结束后,用var i
定义的变量i
此时等于6- 依次执行五个定时器,都打印变量
i
,所以结果是打印5次6
第一种改进方法:利用IIFE(立即执行函数表达式)
当每次for
循环时,把此时的i
变量传递到定时器中
for(var i=1;i<=5;i++){ (function(j){ setTimeout(function timer(){ console.log(j) }, i*1000) })(i) }
第二种方法:setTimeout
函数的第三个参数,可以作为定时器执行时的变量进行使用
for(var i=1;i<=5;i++){ setTimeout(function timer(j){ console.log(j) }, i*1000, i) }
第三种方法(推荐):在循环中使用let i
代替var i
for(let i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i) }, i*1000) }
如若转载,请注明出处:开源字节 https://sourcebyte.cn/article/144.html