likes
comments
collection
share

闭包:我标记了一处“地点”

作者站长头像
站长
· 阅读数 22

前面我们已经介绍了js中作用域以及预编译的概念,正是因为它们俩规则的冲突碰撞下,就萌生出了闭包的概念,闭包在js中也是很重要的。

闭包:我标记了一处“地点”

闭包

今天我们就来聊聊什么是闭包?闭包(Closure),它指的是一个函数能够访问并记住其自身作用域以外的变量的能力。具体来说,当一个内部函数引用了外部函数的变量时,就形成了一个闭包。这个内部函数可以访问外部函数的局部变量即使外部函数已经执行完毕,只要内部函数还被引用,这些外部变量就不会被销毁,从而形成了一个“封闭”的环境

从概念上看,比较难理解闭包;首先让我们来看以下一段代码:

function bar() {
    console.log(a);
}
function foo() {
    var a = 100
    bar()
}
var a = 200
foo();

在我们之前学过的知识中,我们会默认它应该是打印100;因为在调用栈中,函数bar应该会去foo词法环境中找到定义的变量a=100,然后再将其打印,可结果真是如此吗?

闭包:我标记了一处“地点”

结果打印出来是全局中声明的变量200;在这里就要明白作用域链的概念了。

作用域链

每个函数在执行前会进行预编译,会创建执行上下文对象,在每一个执行上下文对象中还有一个内置属性outer,内定的outer属性用于指明该函数的外层作用域是谁,而outer属性的指向怎么判断呢?规则是,outer的指向是根据词法作用域来定的。

在js引擎在查找变量时会先在函数中查找,找不到就会根据outer的指向去到外层作用域中查找,层层往上,这种查找的关系链就称为作用域链

闭包:我标记了一处“地点”

根据上图,就可以得出上面代码的执行结果应该是全局作用域中的200

词法作用域

关于outer属性的指向问题,我们还得知道js中词法作用域的概念;在词法作用域中,变量的可访问性取决于它们在源代码中的位置,即它们在代码中的“词法”或“语法”位置,而不是它们在运行时的位置一个域所处的环境,是由函数声明的位置来决定的

也就是说,变量的可见性和生命周期在编译阶段就可以确定,而不依赖于程序运行时的动态行为。

闭包

同样地,让我们再来看下面一段代码;

function foo(){
    var name = 'kun'
    function bar(){
        console.log(count,age);
    }
    var count = 1;
    var age = 18;
    return bar
}
var age = 20
const baz = foo();
baz()

这是一个嵌套函数,并且内部函数被返回到外面使用;正因为内部函数被返回到外面使用,这时在调用栈中,函数foo的调用就已经完成了,按理来说foo的执行上下文对象应该出栈销毁;但是又根据作用域的规则:内部作用域可以访问外部作用域;这时在外面调用的bar函数,根据outer的指向应该要到函数foo里面查找属性age,但是foo的执行上下文对象不是被销毁了吗?这时候,就要引入闭包了。

闭包:我标记了一处“地点”

因为作用域的规则,所以函数foo为它的内部函数bar留下了一个小背包,里面包含着函数foo里面的变量,这个“背包”就被称为闭包

闭包 面试题

在了解完闭包后,我们可以来看一个面试常考题;

var arr = []

for (var i = 0; i < 10; i++){
    arr[i] = function() {
        console.log(i);
    }
}

arr.forEach(function(item){
    item()
})

面试官:怎么把上面的代码改成正常预期输出?

这里考察的就是对闭包的使用:

var arr = []
for(var i = 0; i <10; i++) {
    function foo(){
        var j = i
        arr[j] = function() {
            console.log(j);
        }
    }
    foo();
}

arr.forEach(function(item){
    item()
})

上面就是把变量i逐个储存到函数foo的闭包之中,然后调用内部函数时就能够访问到i的值。

小结

根据js词法作用域的规则,内部函数总是能访问外部函数中的变量,当通过调用一个外部函数返回的一个内部函数后,即使外部函数执行已经结束了,但是内部函数引用了外部函数中的变量也依旧需要被保存在内存中,我们把这些变量的集合叫做闭包

转载自:https://juejin.cn/post/7386958406136004658
评论
请登录