闭包其实很简单

作者: MountainKing | 来源:发表于2015-12-22 23:05 被阅读344次

    什么是闭包

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

    看完概念是不是一头雾水?没关系,我一向不喜欢在概念上理解技术,直接看闭包能解决什么问题。本文采用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
    

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

    相关文章

      网友评论

        本文标题:闭包其实很简单

        本文链接:https://www.haomeiwen.com/subject/mpaphttx.html