闭包
函数被在所定义的词法作用域之外调用,并且访问了所在的词法作用域,就产生了闭包
- 当函数可以记住并访问所在词法作用域的时候,即函数是在当前词法作用域之外执行,就产生了闭包。
- 函数在定义时的词法作用域之外的地方被调用,闭包可以使得函数继续访问所定义时的词法作用域
- 无论通过何种手段将函数传递到所在词法作用域之外,他都会持有对原始定义作用域的引用。
如果将(访问他们各自词法作用域的) 函数当作第一级的值类型并到处传递,就是在使用闭包,比如定时器,事件监听器,ajax 请求,webWork等任务中,只要使用了回调函数,就是在使用闭包
const wait = (message) => {
setTimeout(finction timer() {
console.log(message) // timer 函数具有wait 函数作用域的闭包
}, 1000)
}
wait('hello')
使用场景:
-
封装私有变量
-
延续局部变量寿命
const report = (srcUrl) => { let img = new Image(); img.src = srcUrl; } report('http://localhost:8000')但是可能有个问题,通过img上报数据,但是当report 执行后,可能还没有发起http请求,report函数中局部变量img就被销毁了。所以利用闭包将img封闭
const report = (srcUrl) => { let imgs = []; return (srcUrl) => { let img = new Image(); imgs.push(img) img.src = src; } }
使用闭包是会把一些变量一直保存下来,可能对内存方面有影响,而且使用闭包的同时可能比较容易形成循环引用,这样的话如果垃圾回收机制使用引用计数策略的话,循环引用就会导致内存泄露(所以本质上和闭包没有一毛钱关系),如果要解决,我们可以手动将循环引用的变量设为null.