带有执行环境的函数 - 闭包

学习 JavaScript 的同学都会面对闭包,总觉得很难,你会看到闭包各种版本的定义,即使把闭包的概念背会也不一定的能够理解闭包。想要掌握闭包,需要看很多关于闭包的资料,加上对 JavaScript 执行过程的理解才能掌握闭包。如果你看到“一文读懂闭包”,“十分钟读懂闭包”这类文章后,想「投机取巧」花几分钟时间能够理解闭包,其实是不可能的,一切需要脚踏实地,慢慢就理解了。

「闭包的出现能给编程带来哪些便捷呢?」,这是我们学习闭包首先需要面对的问题,也就是说闭包出现的背景是什么。

函数是无状态的,比如下面的函数:

function call() {
    var name = 'suyan';
    var age = 20;
    console.log(name + ' age is ' + age);
}
call();

当 call 函数执行完后 name 和 age 占用的内存空间将会被释放,在函数外部无法访问变量 name 和 age 。如果想要在函数 call 外访问变量 age,且函数执行完后保留 age 的值,咋么办?

想要解决这个问题,可以使用闭包(colsure)

function call() {
    var name = 'suyan';
    var age = 20;
    console.log(name + ' age is ' + age);
    return {
        getAge: function () {
            return age;
        },
        setAge: function (newValue) {
            age = newValue;
        }
    };
}
const ageObj = call();
console.log(ageObj.getAge()); // 20
// 修改 age 的值为 30
ageObj.setAge(30);
console.log(ageObj.getAge()); // 30

通过 Chrome 调试工具可以查看 call 这个函数捕获的闭包中的变量:

闭包一大重要特征就是可以「保存函数执行环境中的变量」,使其延迟释放,比如下面的函数:

function createCounter() {
    let counter = 0;
    const myFunction = function() {
        counter = counter + 1;
        return counter;
    };
    return myFunction;
}
// increment 是一个函数
const increment = createCounter();
const c1 = increment();
const c2 = increment();
const c3 = increment();
console.log(c1, c2, c3); // 1,2,3

increment 这个函数使用了 createCounter 中的变量 counter,每次调用 increment 这个函数,变量 counter 一直保存在执行环境中,并不会被释放。再创建一个 increment2,这是 c11 的值为 1。可见 increment 和 increment2 使用的执行环境互不影响。

const increment2 = createCounter();
const c11 = increment2();
console.log(c11); // 1

闭包使得一个函数可以访问另一个函数作用域中的变量。我们在看一下 JavaScript 内置对象数组 这节课程中的一道关于闭包的面试题:

(function () {
    var numbers = [];
    for (var i = 0; i < 4; i++) {
        numbers.push(function () {
            return i;
        });
    }
    var result = numbers.map(function (e) {
        return e();
    });
    console.log(result); // 值是什么?
})();
‍

最终打印的值是 4、4、4、4。在函数中通过 var 声明的变量 i 属于函数作用域,当代码执行到第 8 行后, i 的值是 4。此时 numbers 中保存为 4 个函数,当这些函数被执行的时候会使用当前函数执行环境中的变量 i,此时值为 4,故最终 result 中的值都是 4。

如果把上面代码中的 var i = 0;修改成 let i = 0;结果是什么?

总之,闭包可以延长变量的释放,你可以把闭包看做是带有执行环境的函数。


推荐阅读:

看透变量提升与块级作用域实现的原理
执行上下文与调用栈
推荐我精心准备的 JavaScript 学习资源

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值