js的闭包

187 阅读3分钟

一. 什么是闭包

  • 对于什么是闭包,不同的书籍给了不同的描述,咱们先来看看
  • JavaScript高级程序设计》这样描述:

闭包是指有权访问另一个函数作用域中的变量的函数;

  • JavaScript权威指南》这样描述:

从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。

  • 你不知道的JavaScript》这样描述:

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

  • 不知你是否和我一样,看到之后和我有着一样的表情😂
  • 说到闭包,首先我们得了解一个东西GC,也叫垃圾回收,那它存在得意义是什么呢?就是为了替程序员去释放内存,不用的东西自动释放。说到这里,可能有人会问,那什么东西需要释放,什么东西不需要释放?
  • 从底层来说:在计算机真正执行函数的时候,每调用一次函数,都会为这个函数分配一个空间,这个空间叫做栈,整个函数所有的局部变量都在这个函数里跑,函数执行会分配,函数结束会回收,这是一个栈的本质,闭包能做到函数执行完了,这个栈也不回收,这就叫闭包。
  • 从上层来说:把函数当作对象处理,函数调用的时候,它就会创建一个对象出来,这个对象就能包括这个函数里面各种执行的细节,到时候要回到哪去,谁调用的等等这一系列东西,这就是一个闭包的本质。
  • 那到底什么是闭包呢?
    • 简单来说,闭包是指可以访问另一个函数作用域变量的函数,一般是定义在外层函数中的内层函数。

二. 为什么要用闭包

  • 局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。

三. 闭包自身的特点

  • 占用更多内存
  • 不容易被释放

四. 闭包的实例

  • 示例1
    function fn1() {
    	var name = 'iceman';
    	function fn2() {
    		console.log(name);
    	}
    	fn2();
    }
    fn1();
    
  • 示例2
    function fn1() {
    	var name = 'iceman';
    	function fn2() {
    	    console.log(name);
    	}
    	return fn2;
    }
    var fn3 = fn1();
    fn3();
    
    • fn2的词法作用域能访问fn1的作用域
    • 将fn2当做一个值返回
    • fn1执行后,将fn2的引用赋值给fn3
    • 执行fn3,输出了变量name
  • 示例3
    function fn1() {
    	var name = 'iceman';
    	function fn2() {
    		console.log(name);
    	}
    	fn3(fn2);
    }
    function fn3(fn) {
    	fn();
    }
    fn1();
    
    • 本例中,将内部函数fn2传递给fn3,当它在fn3中被运行时,它是可以访问到name变量的。

五.总结

  • 某个函数在定义时的词法作用域之外的地方被调用,闭包可以使该函数极限访问定义时的词法作用域。