目录
- 1、什么是闭包,什么是作用域
- 1.1 变量作用域
- 1.2 闭包是啥?如何改变变量调用格局
- 1.3 闭包的特性
- 2、怎么用闭包,闭包实例应用
- 2.1 常见闭包实例
- 2.2 闭包异步函数的应用
- 2.3 柯里化的应用
- 3、闭包的优缺点
- 3.1 优点
- 3.2 缺点
- 4、片尾彩蛋
【写在前面】2023年确实想整理好一些前端的学习心得,另外也秉着不让后学习者少走弯路的原则,博主是日夜挑灯阅尽千篇才整理出来的,闭包一直是面试高频词汇,也是很多高级应用必不可缺的,下面务必给我三分钟,让我为您详细解答一下闭包的前世今生。希望能给您带来帮助。
涉及知识点:变量作用域;闭包;垃圾回收机制,;立即执行函数;闭包异步函数,柯里化
1、什么是闭包,什么是作用域
1.1 变量作用域
闭包理解的前提是我们应该先去理解变量作用域,正常也无外乎全局变量和局部变量;
全局变量能被所有的函数应用,局部变量的话只能在声明区域应用。
好比如下所示的函数:
1
2
3
4
5
6
7
8
9
10
11var hdd = '黄大大'; function hddFunc(){ var kf = '黄小小'; console.log(hdd+'好帅'); } function kongfu(){ console.log(kf+'好丑'); } hddFunc(); //输出黄大大好帅 kongfu(); //输出报错,VM138:7 Uncaught ReferenceError kf is not defined
从上面的实例我们不难发现,全局变量谁都能动,局部变量只能在自己地盘使用。
1.2 闭包是啥?如何改变变量调用格局
要是我函数体内就要用外部的变量呢?也不是不可以,接下来看下面这个实例
1
2
3
4
5
6
7
8
9
10
11var hdd = '黄大大'; function hddFunc(){ var kf = '黄小小'; console.log(hdd+'好帅'); function kongfu(){ console.log(kf+'好丑'); } } hddFunc(); //输出黄大大好帅 kongfu(); //输出报错,VM138:7 Uncaught ReferenceError kf is not defined
输出结果还是一样的。那么我将kongfu()调用放在hddFunc()体内呢?如下所示调整:
1
2
3
4
5
6
7
8
9
10
11
12
13var hdd = '黄大大'; function hddFunc(){ var kf = '黄小小'; console.log(hdd+'好帅'); function kongfu(){ console.log(kf+'好丑'); } kongfu(); } hddFunc(); //输出黄大大好帅 //输出黄小小好丑
从这个实例不难发现只有在变量声明区内调用才有效,也确实是实现了kongfu()函数输出了非自身区域内变量的值。其实到这里我就讲完了闭包。
总之一句话:
闭包就是指内部函数有权访问到外层函数的作用域,能读取到外层函数作用域声明的变量,或者我们可以将变量kf和函数kongfu()之间的环境(桥梁)叫做闭包,特别要注意的是必须得在父函数内调用。
1.3 闭包的特性
从上面我们可以特别清楚的看的出来,首先是函数内声明函数,其次是函数内部调用外部参数,再者就是回收机制。
其实在上面的函数调用过程中hddFunc函数体内声明的变量kf因为有kongfu()函数的使用,所以永远不会销毁,正常函数体内的局部变量会随着函数执行完成后而销毁。因此在这里我总结一下闭包三大特性:
- 函数嵌套函数;
- 函数内部可调用外层函数声明的变量和参数;
- 闭包机制下的参数和变量是不会被垃圾回收机制回收(销毁);
2、怎么用闭包,闭包实例应用
2.1 常见闭包实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22function hdd() { var sq = 1 function haoshuai() { return ++sq } return haoshuai } var hddhs = hdd(); console.log(hddhs()); //输出 2 function hdd() { var sq = 1 function haoshuai() { return ++sq } return haoshuai } var hddhs = hdd(); hddhs(); console.log(hddhs()); //输出3
小记:从这里不难发现帅气值变量sq始终都是在的,调用一次就会存储一次加一,从这里就可以确定sq这个变量一直没有被回收。
2.2 闭包异步函数的应用
先用实例和大家介绍一下:
1
2
3
4
5
6
7
8
9
10
11for (var i = 1; i < 5; i++) { setTimeout(function () { console.log(i+"-黄大大好帅"); }, 50); } //输出: 5-黄大大好帅 5-黄大大好帅 5-黄大大好帅 5-黄大大好帅
但是我就是想让他在遍历里面按照正常顺序来输出。这个时候我们可以用到闭包的概念。我们创建了一个立即执行函数,将变量i放在立即执行函数内,其实也就相当于这里的i被setTimeout异步函数给引用了,从而实现i变量叠加后会保存原有的值。也验证了一点特性,函数嵌套函数的说法
1
2
3
4
5
6
7
8
9
10
11
12
13for (var i = 1; i < 5; i++) { (function(i){ setTimeout(function () { console.log(i+"-黄大大好帅"); }, 50); })(i) } //输出: 1-黄大大好帅 2-黄大大好帅 3-黄大大好帅 4-黄大大好帅
其实最推崇的应该是下面这个方式,将变量i用let进行声明,因为let所声明的变量只在let命令所在的代码块内有效。如下所示:
1
2
3
4
5
6
7
8
9
10
11for (let i = 1; i < 5; i++) { setTimeout(function () { console.log(i+"、黄大大好帅"); }, 50); } //输出: 1-黄大大好帅 2-黄大大好帅 3-黄大大好帅 4-黄大大好帅
2.3 柯里化的应用
柯里化是函数的一种高阶技术,我们可以理解为函数的一种转换,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//求和函数 function sum(a, b,c) { return a + b+c; } //柯里化辅助函数curry() //curry函数的实现(不知道多少入参,所以用了递归) function curry(fn,arr=[]){ let len = fn.length; //函数的长度是函数形参的个数 return function (...args){ let arrs = [...arr,...args]; if(arrs.length < len){ return curry.call(this,fn,arrs); }else{ return fn(...arrs); } }} let getSum = curry(sum); console.log(getSum(1,2,3)) //輸出6 console.log(getSum(1)(2,3)) //輸出6 console.log(getSum(1)(2)(3)) //輸出6
我们不难发现里面函数嵌套函数,且应用函数体外的变量。
3、闭包的优缺点
3.1 优点
1.能读取函数外层的变量,从而避免全局变量被污染
2.外层变量会一直存在内存中,函数结束后不会被回收机制回收
3.2 缺点
1.正因为不被回收机制,所以会导致内存消耗过大,伸直引发溢出,所以慎用哦!
4、片尾彩蛋
如果觉得这篇文章对您有帮助的话,想支持博主的可以上皇榜看看哟,皇榜点击此处进入
最后
以上就是喜悦身影最近收集整理的关于【面试之闭包】前端面试那些事(2)三分钟深入理解闭包(附详解实例)1、什么是闭包,什么是作用域2、怎么用闭包,闭包实例应用3、闭包的优缺点4、片尾彩蛋的全部内容,更多相关【面试之闭包】前端面试那些事(2)三分钟深入理解闭包(附详解实例)1、什么是闭包,什么是作用域2、怎么用闭包,闭包实例应用3、闭包内容请搜索靠谱客的其他文章。
发表评论 取消回复