闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。
引用自百度百科
关键词:代码段,包有变量不能被其他成员访问的变量,该变量通过触发某个函数更改
例1:看一段ts代码
function setupCounter(element: HTMLButtonElement) {
let counter = 0
const setCounter = (count: number) => {
counter = count
element.innerHTML = `count is ${counter}`
}
element.addEventListener('click', () => setCounter(++counter))
setCounter(0)
}
这是一段闭包代码,setupCounter函数中包了counter这个变量,能使用button的onclick事件绑定的函数(setCounter)触发,每次点击,button内计数加一
例2::再看一段python代码
def myGenerator(start):
count = start
def gen():
nonlocal count
count += 1
return count
return gen
g = myGenerator(5)
for _ in range(3):
print(g())
每次调用g()得到的结果都会加1
让我们逐条翻译闭包的关键词:
- 代码段
函数调用 - 包有变量不能被其他成员访问的变量
私有变量 - 该变量通过触发某个函数更改
访问控制
我们最终得到了结论:闭包等价于函数调用+私有变量+访问控制 = 类
我们用Java 完全可以写成以下代码
/**
* MyGenerator
*/
public class MyGenerator {
private int counter = 0;
public MyGenerator(int start){
this.counter = start;
}
public int Gen(){
this.counter++;
return this.counter;
}
}
public class Main {
public static void main(String[] args) {
var g = new MyGenerator(5)
}
}
以后我们在看js或者其他语言闭包的时候,完全可以按照面向对象的方式进行理解。无非是类+成员+访问控制。一旦我们看到函数内部套函数,找函数内部对外部变量的使用,然后看有没有外部访问控制,如果上述条件都满足,可以断定这是个闭包。例如在第一个js代码中,counter在内部被进行了赋值,最后通过绑定事件 addEventListener的方式导出了访问控制函数。
按照面相对象的理解,我们可以把例2的myGenerator理解为一个微型的构造方法,创建了一个函数对象,使用了start为构造方法的参数,里面包有一个count的私有的变量,最后导出了gen方法导出访问控制函数。这样们也应该能够理解,为什么go以下的代码全部输出为10了。(类比于类里声明方法,声明时候并没有被调用,调用的时候外边的i已经完成的迭代都是10了,i为什么没有被回收可以看看go的逃逸分析,内部匿名方法+内部变量i+外部gorountie调度器调度go func)
func manyRountine(){
i:=1
for (;i<10;i++){
go func(){
fmt.println(i)
}()
}
}
这种闭包的写法,多出现于以函数为第一公民的语言中,例如python,js,go.很优雅的使用闭包来保存函数内部的一个私有变量,利用函数内部和外部的作用域的隔离,轻松的把一个函数变成了一个类,使用函数生成一个对象,调用方法控制对象里面的内容。纯OOP语言例如Java和C#则用的较少,因为语言已经将私有的变量的访问控制完善的相当完美,使用闭包纯粹是有些多余了,除了少许的例外,例如内部类,lambda表达式等,需要传递实现类的地方。
由此我们可以看到,无论是面向对象编程,还是函数式编程,无非是一种思想的不同表述方式而已。没有什么高下好用之分,无非是换个说法而已。
因此,在我们学习一门技术的时候,语言,语法,实现层面的东西往往每一种语言的实现方式各有不同,我们需要找到背后解决问题的思想,为什么这个思想可以解决问题。语言没有什么高下之分,只有适合的场景不同,不同的语言解决的问题不同而已。
以下是我个人的总结语言适应的方面:
Java: 工程化,标准化
Python: 快速实现想法
Go: 体积小,编译快,快速部署
js: 浏览器端唯一指定语言,可以理解为浏览器的汇编码,正在被高级的TS取代
C/C++: 底层,快速,直接操作硬件
欢迎补充