对闭包的一些思考?

252 阅读3分钟

面试中一定会被问到的一个问题就是什么是闭包? 要想回答好这个问题除要懂得它的概念之外,还需要明白我们在日常开发中什么情况下会使用闭包,这样才能做到知行合一。以下是我关于这个问题的一些理解,我将通过提问的方式去深入的理解。

什么是闭包?

看了很多文章和资料后,我找到了自认为最有概括性的一句解释“闭包是指有权限访问另外一个函数作用域中的变量的函数”,引自《javascript高级程序设计》,通过这句话我们可以得到这样的理解和疑问:

  • 闭包是一种特殊情况下的函数。
  • 什么是作用域呢?
  • 为什么闭包有权限访问其他函数的变量呢?
  • 什么样的特殊情况会产生闭包?
  • 实际开发中哪里用到闭包呢?

在解答这些问题前,我们先代码展示一下闭包:

var gender
function person(){
    var name = 'leo'
    console.log(gender)
    return function(){
        var gender = 'male'
        console.log(name)
    }
}
var sayName = person(); // 打印undefined 因为person函数中取不到gender的值
                        // 当我们调用person函数的时候,返回的这个函数就是闭包
sayNmae()               // 打印leo
                        // 根据定义因为sayName函数可以访问到person函数里的变量,
                        // 所有sayName函数就是闭包

什么是作用域呢?

作用域就是函数或者变量的可访问范围,在js中我们常听到的是全局作用域和函数作用域,从上面的代码示例中我们可以发现执行sayName函数的时候可以访问到变量name,但是第三行代码执行结果却是undefined,我们可以发现它打印的是我们第一行定义的变量,而不是第六行的那个gender,可以看出不同函数中去取变量的时候,范围是不一样的。为什么会出现这样的情况呢,查阅质量后,我发现作用域是在创建执行上下文的时候创建的,所以要搞懂作用域,我们要先弄懂下面的问题。

什么是执行上下文?

执行上下文就是函数执行的环境,还是上面的代码,首先只要在能运行js的地方(比如我们打开一个chrom的tab页),就会首先先执行一个main函数,执行完后,就创建了一个js的执行环境,这个环境一定会有的一个可访问对象就是window,我们把这个执行环境叫做执行上下文,创建执行上下文的同时会创建一个和上下文相关联的对象,这个对象中包含了作用域链、函数中的变量。每创建一个执行上下文就会把当前的作用域和包裹当前函数的函数的作用域合并起来,这就形成了作用域链。

什么是执行栈?

就是存放执行上下文的一个栈结构,我们都知道js是单线程的,每次只能执行一个任务,在执行代码的时候也是一样的,执行栈中存放了所有将要被执行的代码的执行上下文,每次执行完后会做出栈的操作,如果上下文中的变量没有被引用的话,就会销毁执行上下文。

综上

我觉得在js中所有的函数其实都是闭包,因为js中一定会有一个全局的执行上下文,并且只要不关闭浏览器的话,这个执行环境就一定会存在,并且这里面的变量,我们在其他函数里面都是可以访问到,比如window。就如同开篇说的“闭包是指有权限访问另外一个函数作用域中的变量的函数”。以上为个人见解,欢迎指证。