什么是闭包
闭包是函数式编程基石,在形式上就是一个函数内部定义另一个函数,函数的堆栈在在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。
看完概念是不是一头雾水?没关系,我一向不喜欢在概念上理解技术,直接看闭包能解决什么问题。本文采用JS代码辅助理解,虽然JS是一门设计糟糕、备受吐槽的语言,但是JS的闭包特性是90年代以后所有语言里最好的。
用途
- 访问权限控制
面向对象语言如Java、C++都会有private、public关键字,不允许从类外部直接访问特定成员变量,需要通过成员函数来访问,这是一个很普遍、很合理的需求。
先复习一下JS的变量作用域。
函数内部可以访问全局变量:
var n=1;
function print(){
console.log(n);
};
print(); // 1
但是从函数外部不能访问函数内部变量:
function fun() {
var a = 0;
};
console.log(a); // error
于是闭包派上用场了:
function outer() {
var n = 2;
function inner() {
return n;
};
return inner();
}
var result = outer();
console.log(result); // 2
- 延长变量生命周期
在面向对象语言里,函数内的变量都是在栈上分配的,函数调用完成后,栈销毁,变量的生命周期结束。而对象是在堆分配的,会常驻内存,除非被手动或自动回收掉。
闭包再次救场:
function createCounter() {
var counter = 0;
function increment() {
counter = counter + 1;
console.log("Number of events: " + counter);
}
return increment;
}
var incr = createCounter();
incr(); // 1
incr(); // 2
incr(); // 3
函数式编程
近几年,老古董函数式编程大有卷土重来、取代面向对象的趋势,我一向认为一门新技术要证明自己牛逼,最好的策略不是去炫技,因为很多看客好奇心不强、学习能力一般,很容易就被吓跑了。毕竟技术是来解决问题的,下面我分别用Java和JS实现一个能自增自减的程序,看看两者有啥区别。
Java:
public class Counter {
private int counter;
public Counter() {
counter = 0;
}
public int getCounter() {
return counter;
}
public void incr() {
++counter;
}
public void decr() {
--counter;
}
public static void main(String[] args) {
Counter counter = new Counter();
counter.incr();
counter.incr();
counter.decr();
System.out.println(counter.getCounter()); // 1
}
}
JS:
function Counter() {
var counter = 0;
function incr() {
++counter;
}
function decr() {
--counter;
}
function getCounter() {
return counter;
}
return {
incr: incr,
decr: decr,
getCounter: getCounter
}
}
var counter = Counter();
counter.incr();
counter.incr();
counter.decr();
console.log(counter.getCounter()); // 1
剥离函数式编程天生的骄傲,排除外界的干扰,还原它的本质。至于面向函数和面向对象哪个好,不是三言两语能说清楚的,待我日后再更。
网友评论