当我们在谈论编程的时候,我们在谈论什么

闭包其实很简单

2015-12-22  本文已影响344人  MountainKing

什么是闭包

闭包是函数式编程基石,在形式上就是一个函数内部定义另一个函数,函数的堆栈在在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。

看完概念是不是一头雾水?没关系,我一向不喜欢在概念上理解技术,直接看闭包能解决什么问题。本文采用JS代码辅助理解,虽然JS是一门设计糟糕、备受吐槽的语言,但是JS的闭包特性是90年代以后所有语言里最好的。

用途

  1. 访问权限控制

面向对象语言如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
  1. 延长变量生命周期

在面向对象语言里,函数内的变量都是在栈上分配的,函数调用完成后,栈销毁,变量的生命周期结束。而对象是在堆分配的,会常驻内存,除非被手动或自动回收掉。
闭包再次救场:

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

剥离函数式编程天生的骄傲,排除外界的干扰,还原它的本质。至于面向函数和面向对象哪个好,不是三言两语能说清楚的,待我日后再更。

上一篇 下一篇

猜你喜欢

热点阅读