什么是闭包?对于JavaScript中闭包的见解:


前言

闭包是一个复杂的概念,要掌握闭包,需要对JS的编译要有所了解,可以参考:
链接: JavaScript中的代码是怎么编译执行.
链接: JavaScript中的全局变量以及局部变量.


一、闭包是什么?

闭包(closure)是指有权访问另一个函数作用域中的变量的函数。 ----JavaScript高级程序设计

函数对象可以通过作用域链相互关联起来,函数体内部的变量可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。 ----JavaScript权威指南

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

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。 ---- MDN官方文档


简单理解就是:一个作用域可以访问另一个函数内部的局部变量。


例1、看下面的例子:

	function f1() {
        var a = 2;
        function f2() {
            console.log(a);  // 2
        }
        f2();
    }
    f1();

闭包:对f2() 这个函数作用域,访问了另一个函数 f1() 里面的局部变量a,就产生了闭包。

断点调试:

  1. f1()开始执行:
    第一步我们可以看见全局作用域
  2. 进入局部作用域:
    在这里插入图片描述
  3. 执行f2()
    在这里插入图片描述
    此时可以看见,已经产生了闭包 f1()
  4. 展开来看,可以看见闭包f1()中的内容为a : 2
    在这里插入图片描述

由此可知,在f2()函数内部访问了f1()内部的局部变量a,此时f1()是一个闭包函数(局部变量所在的函数就是闭包函数)。链接: 代码地址.

  • 引用小黄书上的话:
    从技术上来讲,这是闭包,但根据定义,确切来说这并不是闭包。
    从纯学术的角度说,在上面的代码片段中,函数f2()中具有一个涵盖f1()作用域的闭包(事实上,涵盖了它能访问的所有作用域,比如全局作用域)。也可以认为f2()封闭在了f1()的作用域中,因为f2()嵌套在f1()内部。

例2、再看下面的例子,清晰的展示了闭包:

	function f1() {
        var a = 2;
        function f2() {
            console.log(a); 
        }
        return f2;
    }
    var f = f1();
    f();  // 2 

与例1一样,函数 f2() 的词法作用域可以访问 f1() 的内部作用域。

  • 在这个例子中,f2() 函数本身当做一个值类型进行传递,并且将 f2() 所引起的函数对象本身当做返回值。
  • 来看一下 f1() 的执行:
    在这里插入图片描述
    在这里插入图片描述
  • f1() 执行后,其返回值(也就是内部的 f2() 函数)赋值给变量 f 并调用函数 f(),实际上只是通过不同标识符的引用调用了内部函数的函数 f2()
    在这里插入图片描述
  • 此时可以看见, f2() 显然可以正常被执行。
    在这里插入图片描述
  • 它(f2)在自己定义的词法作用域之外的地方(f1())执行。
  • 你也可以自己调试.

关于垃圾回收机制:

  • 原本f1()在执行后,通常在f1()整个内部的作用域都会被销毁,这是因为引擎有垃圾回收机制来释放内存。
  • 然而在闭包中,f1()内部作用域依然存在,并没有被回收(是因为仍有函数在使用这个作用域)。
    – 而使用这个内部作用域的正是函数f2()

结论1: f2() 依然持有对f1() 作用域的引用,这个引用就叫做闭包。
结论2: f1() 就是这个闭包函数。


二、闭包的作用

  • 以例2为例,闭包可以实现 f1() 外部的作用域,访问到 f1() 内部作用域。(而在常规函数中这样是不可以的)
  • 例2与例1不同之处在于:例2实现了外部函数 f() 访问到了 f1() 的内部变量。
  • 例2本质上相当于执行了:
	var f = function f2() {
		console.log(a)
	}

例2的代码,效果等同于下面:例3:

	function f1() {
        var a = 2;
        return function f2() {
            console.log(a); 
        }
    }
    var f3 = f1();
    f3();  // 2 

例3的执行,相当于执行 f3() 时,直接执行 f2() 并且访问的作用域是 f1() 的作用域。

  • 因此,可以知道:f1() 外面的作用域(f3())可以访问 f1() 内部的局部变量(a = 2)。
  • 这里可以讨论一下 return 的作用:
    当需要全局作用域(f3())需要访问局部作用域 f1() 时, return 的作用就体现出来了。
    *这等同于外部作用域访问内部作用域。而例1是内部作用域访问外部作用域。

结论:闭包的主要作用:延伸了变量的作用范围


总结

这里对文章进行总结:

理解闭包,闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
不断学习,共同进步,希望文章对你有所帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值