// 未柯里化之前
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');
闭包
是面试经常考的,也是了解一个程序员基础知识一个重要点,本篇是笔着对于闭包
的理解,希望在实际项目中有所思考和帮助。正文开始...
闭包是什么
我们可以从以下几点来理解
一个函数
对其周围状态
的引用
并捆绑在一起的一种组合
一个函数
被引用
包围一个内部函数
能访问外部函数
的作用域
我们来看一张图理解下上面三句话
对应代码如下
我们注意到在
A
函数中,我们创建了两个内部的私有变量name
、age
,并且我们在A
函数中创建一个内部函数B
,此时在B
函数中,我们会发现在B
内部可以访问它周围状态(变量)
,也就意味着在B
函数内部可以访问外部函数
的作用域。至此你会发现,
闭包
就是在B
函数一创建,并且有对周围的状态
有引用,那么此时闭包
就出现了,也就是说,闭包就是一座桥梁,能让B
函数内部能突破自身作用域
访问外部
的变量。不知道你有没有发现,我在
A
内部定义的变量,我在外部并不能访问,也就是说相对A
的外部,A
内部所有的变量都是私有的
,在A
定义的变量,相对于B
中,又可以访问。因为B
函数能访问A
中的变量,也正是依靠闭包
这座桥梁。闭包的特性
1.
创建私有变量
2.
延长变量的生命周期
我们知道
闭包
会造成内存泄露,本质上就是创建的变量一直在引用内存中,当一个普通函数被调用结束时,函数内部创建的变量就会被销毁。但是闭包会保存其变量的引用,即便外部执行上下文被销毁,但是闭包内创建的词法环境依然还在,我们看下面代码具体理解下。
在
A
中返回了函数B
,实际上就是返回了一个函数,当我们我们用var b1 = A()
申明一个变量时,实际上,这里内部B
还没有执行,但是在执行A()
方法时,返回的是一个函数,所以我们继续执行b1()
,我们尝试调用三次,我们会发现打印出来的值是1,2,3
,这就说明,闭包
延长了变量的生命周期,因为第三次与第二次打印出来的值就是同一个值的引用。 具体一张图可以可以理解下当我们用
var b1 = A()
时,实际上,我用蓝色的方框已经标注起来了,在b1
内部我们可以看到,每执行b1
,实际就是执行的红色
区域的函数,也就是A
内部定义的函数B
,但是每次调用b1
,我们看到都有保留age
的引用,所以你看到age
依次就是1,2,3
,所以也就证实了闭包能延长变量的生命周期
,并且闭包创建的私有变量
可以减少全局变量的使用。通常我们知道尽量少创建全局变量,因为我们不知道这个全局变量什么时候使用,只有在被使用的时候才会被释放。
闭包也是解决了全局变量命名冲突的问题
,因为创建的私有变量,没法在外部访问,这样也就减少了变量名
污染的问题。等等,还有一个问题,如果我把上面的代码改成下面呢?
你会发现,我两次打印的都是同一个
1
,这是为什么呢?你有没有发现之前我们是用var b1 = A()
申明的一个变量,实际上这句代码就是js
新开辟暂存了一块空间,因为A
内部返回的是一个函数,当我每次调用b1
时,实际上是调用返回的那个函数,因为函数内部存在闭包的引用,所以一直就1,2,3
,但是我这里我使用的是A()()
,我们发现每次都是1
,说明当我第二次调用时内部的age
已经重新定义了一遍,而并没有引用上一次的值,这就说明,在A()
立即调用时,闭包内部引用的变量已经被释放。由于闭包
也会有缺陷,创建太多的闭包会造成消耗内存严重,影响网页性能。应用场景
柯里化函数
回调函数
计数器
、延迟调用(防抖与节流)
实际上就是把一个函数的多个参数拆分成多个函数调用,主要目的是
避免平繁调用具有多个相同参数函数,又可以复用相同函数
,具体可以用下面代码理解下函数柯里化后
上面 🌰 好像还是不太明显,在具体业务中,你可能会写出这样的代码
改成函数柯里化后
我们发现改完后,貌似柯里化后,代码反而变多了,但是代码的可读性以及拓展性比以前更友好,这点因特殊业务功能而定,也不是非要把用柯里化函数去处理所有的业务,具体因情况而定,这里只是举了个简单的例子。
回调函数
在业务中使用的太多了,具体可以看下下面这个简单的例子,写一段为伪代码感受一下这个就非常典型了,比如说一个循环里面
频繁触发事件,在指定一段时间内调用函数
利用定时器做缓冲器,当第二次调用时,清除上一次的定时器,在指定时间内重新调用函数
以上案例都有用到
闭包
,闭包的身影无处不在,只是我们用的时候,我们并没有发现。总结
闭包
的概念,闭包是一个函数
对其周围状态
的引用
并捆绑
在一起的一种组合,或者是一个函数
被引用
包围,或者是一个内部函数
能访问外部函数
的作用域闭包的特性,
创建私有变量
和延长变量的生命周期
闭包的应用场景,
柯里化函数
、回调函数
、定时器
、节流/防抖
等本文示例code example
最后,喜欢的点个赞,在看,转发,收藏等于学会,欢迎关注 Web 技术学苑,好好学习,天天向上!