闭包

123 阅读2分钟

闭包

函数被在所定义的词法作用域之外调用,并且访问了所在的词法作用域,就产生了闭包

  • 当函数可以记住并访问所在词法作用域的时候,即函数是在当前词法作用域之外执行,就产生了闭包。
  • 函数在定义时的词法作用域之外的地方被调用,闭包可以使得函数继续访问所定义时的词法作用域
  • 无论通过何种手段将函数传递到所在词法作用域之外,他都会持有对原始定义作用域的引用。

如果将(访问他们各自词法作用域的) 函数当作第一级的值类型并到处传递,就是在使用闭包,比如定时器,事件监听器,ajax 请求,webWork等任务中,只要使用了回调函数,就是在使用闭包

const wait = (message) => {
  setTimeout(finction timer() {
    console.log(message)  // timer 函数具有wait 函数作用域的闭包
  }, 1000)
}
wait('hello')

使用场景:

  1. 封装私有变量

  2. 延续局部变量寿命

    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.