前言
谈起闭包,我想接触过JS的读者都不陌生。闭包是JavaScript两个核心技术之一(另一个是异步),作为衡量JS工程师实力的一个重要指标,我们在面试及实际应用中都离不开它
定义
《JavaScript高级程序设计》(第四版)中是这么写的:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的,通俗的来说,就是一个内部函数即使在其外部函数被返回之后仍然可以访问其所在的外部函数中声明的变量和参数,这就是闭包。而且在JavaScript中除了用new Function构建的函数,其它函数都是天生闭包的。
闭包基础
要想深入理解什么是闭包,首先要对以下内容有所掌握:
- 在调用一个函数时,会为这个函数调用创建一个执行环境(执行上下文栈),并创建一个作用域链,然后用arguments和其他命名参数来初始化这个函数的活动对象
- 作用域链的本质是一个指向变量对象的指针列表,而外部函数的活动对象就是内部函数作用域链上的第二个对象,这个作用域链一直向外串起了所有包含调用函数的活动对象,直到全局执行上下文才终止
- 执行环境(执行上下文栈)意味着定义了变量或函数有权访问的其他数据,而每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都会保存在这个对象中
- 当执行流进入一个函数时(调用函数),函数的执行环境就会被推入到一个环境栈中,直到函数执行完毕环境栈就会把该函数的执行环境弹出,把控制权返回之前的执行环境
- 垃圾回收机制:一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间,以便后面的语句所用,等到函数执行完毕返回后,这些对象就会被认为是无用了,对应的内存空间就会被回收。待到下次在执行此函数时,所有变量又回到最初的状态,重新赋值使用
闭包作用
都说闭包重要,那么闭包到底可以用来做什么呢?
访问函数内部变量,保持函数在环境中一直存在,不会被垃圾回收机制处理
function foo() {
let value = 1;
function bar() {
console.log(value);
}
return bar();
}
const baz = foo();
// 1
如上,bar包含foo内部作用域的闭包,使得该作用域能够一直存活,不会被垃圾回收机制处理掉,以供bar在任何时间进行引用
闭包优缺点
优点: 能够让希望一个变量长期驻扎在内存之中成为可能,同时避免了全局变量的污染,以及允许私有成员的存在
缺点: 如果常驻内存会增大内存使用量,并且使用不当容易造成内存泄漏
闭包案例
计数器的实现
function counter() {
let count = 0;
return function() {
return count++;
}
}
let c = counter();
// 由于使用了闭包,重复调用counter函数时变量时count不会被重新赋值
console.log(c());
// 0
console.log(c());
// 1
console.log(c());
// 2
编写一个像sum(a)(b) = a+b这样工作的sum函数
function sum(a) {
return (b) => {
return a + b;
}
}
console.log(sum(1)(2));
// 3
console.log(sum(5)(-10));
// -5
参考文献
- 《JavaScript高级程序设计》(第四版)
- JavaScript Guidebook
- 现代JavaScript教程
后话
- 今天体测一千米,差点出了四分钟,真的是大一入学即巅峰,一年不如一年
- 感觉现在积累的还是太少了,我就像一个缝纫机,每天定好主题就各种找资料,然后再缝缝补补,啊,我还是个菜鸡
- 尚硅谷放在B站的Vue全家桶真实业界良心,越看越起劲,视频一刷就几个小时,至于动手能力嘛......真的,自己啥水平敲敲才知道【万分悲伤】
- 渐渐的,我也要成为标题狗了,罪恶啊