当前位置:网站首页>掌握闭包,夯实基本功
掌握闭包,夯实基本功
2022-07-28 12:48:00 【Maic】
闭包在程序中无处不在,通俗来讲
闭包就是一个函数对其周围状态的引用并捆绑在一起的一种组合,你也可以理解成一个函数被引用包围或者是一个内部函数能够访问外部函数的作用域
闭包是面试经常考的,也是了解一个程序员基础知识一个重要点,本篇是笔着对于闭包的理解,希望在实际项目中有所思考和帮助。
正文开始...
闭包是什么
我们可以从以下几点来理解
- 闭包是
一个函数对其周围状态的引用并捆绑在一起的一种组合 一个函数被引用包围一个内部函数能访问外部函数的作用域
我们来看一张图理解下上面三句话
对应代码如下
function A() {
var name = 'Maic',age = 0;
function B() {
console.log(name, age);
}
}
A();
// console.log(name) name is not defined
我们注意到在A函数中,我们创建了两个内部的私有变量name、age,并且我们在A函数中创建一个内部函数B,此时在B函数中,我们会发现在B内部可以访问它周围状态(变量),也就意味着在B函数内部可以访问外部函数的作用域。
至此你会发现,闭包就是在B函数一创建,并且有对周围的状态有引用,那么此时闭包就出现了,也就是说,闭包就是一座桥梁,能让B函数内部能突破自身作用域访问外部的变量。
不知道你有没有发现,我在A内部定义的变量,我在外部并不能访问,也就是说相对A的外部,A内部所有的变量都是私有的,在A定义的变量,相对于B中,又可以访问。因为B函数能访问A中的变量,也正是依靠闭包这座桥梁。
闭包的特性
1.创建私有变量
2.延长变量的生命周期
我们知道闭包会造成内存泄露,本质上就是创建的变量一直在引用内存中,当一个普通函数被调用结束时,函数内部创建的变量就会被销毁。
但是闭包会保存其变量的引用,即便外部执行上下文被销毁,但是闭包内创建的词法环境依然还在,我们看下面代码具体理解下。
function A() {
var name = 'Maic',age = 0;
function B() {
age++;
console.log(name, age);
}
return B
}
var b1 = A();
b1(); // 1
b1(); // 2
b1(); // 3
在A中返回了函数B,实际上就是返回了一个函数,当我们我们用var b1 = A()申明一个变量时,实际上,这里内部B还没有执行,但是在执行A()方法时,返回的是一个函数,所以我们继续执行b1(),我们尝试调用三次,我们会发现打印出来的值是1,2,3,这就说明,闭包延长了变量的生命周期,因为第三次与第二次打印出来的值就是同一个值的引用。具体一张图可以可以理解下
当我们用var b1 = A()时,实际上,我用蓝色的方框已经标注起来了,在b1内部我们可以看到,每执行b1,实际就是执行的红色区域的函数,也就是A内部定义的函数B,但是每次调用b1,我们看到都有保留age的引用,所以你看到age依次就是1,2,3,所以也就证实了闭包能延长变量的生命周期,并且闭包创建的私有变量可以减少全局变量的使用。
通常我们知道尽量少创建全局变量,因为我们不知道这个全局变量什么时候使用,只有在被使用的时候才会被释放。闭包也是解决了全局变量命名冲突的问题,因为创建的私有变量,没法在外部访问,这样也就减少了变量名污染的问题。
等等,还有一个问题,如果我把上面的代码改成下面呢?
function A () {
var name = 'Maic',age = 0;
function B() {
age++;
console.log(name, age);
}
return B
}
A()(); // 1
A()(); // 1
// var b1 = A();
// b1();
// b1();
// b1();
// console.log(name)
你会发现,我两次打印的都是同一个1,这是为什么呢?你有没有发现之前我们是用var b1 = A()申明的一个变量,实际上这句代码就是js新开辟暂存了一块空间,因为A内部返回的是一个函数,当我每次调用b1时,实际上是调用返回的那个函数,因为函数内部存在闭包的引用,所以一直就1,2,3,但是我这里我使用的是A()(),我们发现每次都是1,说明当我第二次调用时内部的age已经重新定义了一遍,而并没有引用上一次的值,这就说明,在A()立即调用时,闭包内部引用的变量已经被释放。由于闭包也会有缺陷,创建太多的闭包会造成消耗内存严重,影响网页性能。
应用场景
柯里化函数回调函数计数器、延迟调用(防抖与节流)
- 柯里化函数
实际上就是把一个函数的多个参数拆分成多个函数调用,主要目的是避免平繁调用具有多个相同参数函数,又可以复用相同函数,具体可以用下面代码理解下
// 未柯里化之前
function sum(a,b,c) {
return a+b+c
}
sum(1,2,3)
函数柯里化后
function sum(a) {
return function(b) {
return function(c) {
return a+b+c
}
}
}
const a = sum(1);
const b = a(2);
const c = b(3);
console.log(c) // 6 or sum(1)(2)(3)
上面好像还是不太明显,在具体业务中,你可能会写出这样的代码
// 根据正则规则校验某个字段
function regKey(reg, val) {
return reg.test(val)
}
var isPhone = regKey(/^1[3,5,7,8,9]\d{9}$/, 13754123124);
const isNumber = regKey(/\d/, 'test');
改成函数柯里化后
function regKey(reg) {
return (val) => {
return reg.test(val)
}
}
const checkPhone = regKey(/^1[3,5,7,8,9]\d{9}$/);
const checkNum = regKey(/\d/);
const isPhone = checkPhone(13754123124) // true
const isNumber = checkNum(123); // true
我们发现改完后,貌似柯里化后,代码反而变多了,但是代码的可读性以及拓展性比以前更友好,这点因特殊业务功能而定,也不是非要把用柯里化函数去处理所有的业务,具体因情况而定,这里只是举了个简单的例子。
- 回调函数
回调函数在业务中使用的太多了,具体可以看下下面这个简单的例子,写一段为伪代码感受一下
const request = (params) => {
const response = {
code: 0,
success: '成功',
data: []
};
return (callback) => {
callback(response);
}
}
const queryList = () => {
const getData = request({pageIndex:1, pageSize: 10});
getData((res) => {
console.log(res) // {code: 0, success: '成功', data: []}
})
}
- 计数器
这个就非常典型了,比如说一个循环里面
for (var i=0;i<10;i++) {
(function() {
var j = i;
setTimeout(() => {
console.log(j)
}, i* 1000)
})()
}
- 函数节流
频繁触发事件,在指定一段时间内调用函数
// 模拟数据请求伪代码
const fetchList = () => {}
let flag = false;
window.addEventListener('scroll', () => {
if (flag) {
return;
}
flag = true;
setTimeout(() => {
flag = false;
fetchList();
}, 500)
})
- 函数防抖
利用定时器做缓冲器,当第二次调用时,清除上一次的定时器,在指定时间内重新调用函数
// 模拟数据请求伪代码
const fetchList = () => {}
const inputDom = document.getElementById('input');
let timer = null;
inputDom.oninput = function() {
if (!timer) {
clearTimeout(timer);
timer = setTimeout(() => {
fetchList();
}, 500)
}
}
以上案例都有用到闭包,闭包的身影无处不在,只是我们用的时候,我们并没有发现。
总结
- `闭包`[1]的概念,闭包是
一个函数对其周围状态的引用并捆绑在一起的一种组合,或者是一个函数被引用包围,或者是一个内部函数能访问外部函数的作用域 - 闭包的特性,
创建私有变量和延长变量的生命周期 - 闭包的应用场景,
柯里化函数、回调函数、定时器、节流/防抖等 - 本文示例code example[2]
最后,喜欢的点个赞,在看,转发,收藏等于学会,欢迎关注公众号Web技术学苑,好好学习,天天向上!
参考资料
[1]闭包: https://vue3js.cn/interview/JavaScript/closure.html#%E4%B8%80%E3%80%81%E6%98%AF%E4%BB%80%E4%B9%88
[2]code example: https://github.com/maicFir/lessonNote/tree/master/javascript/09-%E9%97%AD%E5%8C%85
边栏推荐
- Lyscript get previous and next instructions
- Countdown 2 days! 2022 China Computing Conference: Mobile cloud invites you to meet with computing network for innovative development
- 蓝桥集训(附加面试题)第七天
- Blue Bridge Training (additional interview questions) day 7
- C语言:归并排序
- DOJP1520星门跳跃题解
- 【黑马早报】字节估值缩水,降至2700亿美元;“二舅”视频作者回应抄袭;任泽平称取消商品房预售制是大势所趋;美联储宣布再加息75个基点...
- JWT 登录认证 + Token 自动续期方案,写得太好了!
- Remember to use pdfbox once to parse PDF and obtain the key data of PDF
- Intra prediction and transform kernel selection based on Neural Network
猜你喜欢

使用 IPtables 进行 DDoS 保护

严格模式——let和const——箭头函数——解构赋值——字符串模板symbol——Set和Map——生成器函数

Half wave rectification light LED

比XShell更好用、更现代的终端工具!

30天刷题训练(一)

接口调不通,如何去排查?没想到10年测试老鸟栽在这道面试题上

SAP ui5 fileuploader control realizes local file upload, and trial version of cross domain access error encountered when receiving server-side response

Operator3-设计一个operator

性能超群!牛津&上海AI Lab&港大&商汤&清华强强联手,提出用于引用图像分割的语言感知视觉Transformer!代码已开源...

Deploy application delivery services in kubernetes (Part 1)
随机推荐
朋友发来几个面试题
Tutorial on the principle and application of database system (062) -- MySQL exercise questions: operation questions 32-38 (6)
Li Kou sword finger offer 51. reverse order pairs in the array
P1797重型运输 题解
[ecmascript6] function and its related use
C语言:顺序存储结构的快速排序
【ECMAScript6】Promise
C language: random generated number + merge sort
国产API管理工具Eolink太好用了,打造高效的研发利器
org.apache.ibatis.exceptions.TooManyResultsException的异常排查过程
微信小程序中自定义模板
C语言:优化后的归并排序
To build agile teams, these methods are indispensable
Org.apache.ibatis.exceptions.toomanyresultsexception
最强分布式锁工具:Redisson
R语言检验样本比例:使用prop.test函数执行单样本比例检验计算总体中成功样本比例p值的置信区间(设置conf.level参数指定置信水平、置信区间的大小)
Tutorial on the principle and application of database system (061) -- MySQL exercise: operation questions 21-31 (V)
要想组建敏捷团队,这些方法不可少
You have to apologize if you get involved in the funny shop?
The strongest distributed locking tool: redisson