26.2.15

Python 的闭包和装饰器 — 42区漫游指南 0.1.1 documentation


在“闭包详解”里提到:
  • (简单的说,)这种内部函数可以使用外部函数变量的行为,就叫闭包。

    • 闭包并不是什么新奇的概念,它早在高级语言开始发展的年代就产生了。
    • 闭包(closure)是词法闭包(Lexical closure)的简称
    • 对闭包的具体定义可以分成两类:
      • 一种说法认为闭包是符合一定条件的函数,比如XXX中这样定义闭包:
        • 闭包是在其词法上下文中引用了自由变量的函数
      • 另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。比如XXXX中就有这样的定义:在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包
    • 作者认为:
      • 可以肯定第二种说法更确切:
        • 闭包是函数和引用环境组成的整体。
        • 闭包只是在形式和表现上像函数,但实际上不是函数。
        • 函数是一些可执行的代码,这些代码在函数被定义后就确定了,不会在执行时发生变化,所以一个函数只有一个实例。
        • 闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
        • 所谓引用环境是指在程序执行中的某个点所有处于活跃状态的约束所组成的集合。
          • 其中约束是指一个变量的名字和其所代表的对象之间的联系。
    • 为什么要把引用环境与函数组合起来呢?
      • 这主要是因为在支持嵌套作用域的语言中,有时不能简单直接地确定函数的引用环境。
      • 这样的语言一般具有这样的特性:
        • 函数是一阶值(First-class value),即函数可以作为另一个函数的返回值或参数,还可以作为一个变量的值。
        • 函数可以嵌套定义,即在一个函数内部可以定义另一个函数。
    • 闭包的应用:
      • 闭包可以用优雅的方式来处理一些棘手的问题
          • 有些程序员声称没有闭包简直就活不下去了。
        • 加强模块化
          • 闭包有益于模块化编程,它能以简单的方式开发较小的模块,从而提高开发速度和程序的可复用性。
          • 和没有使用闭包的程序相比,使用闭包可将模块划分得更小
          • 例子:
            • 要处理一个数组中所有的数字:
              • 求和
              • 求积
              • 打印
对这个例子,如果用Java来实现应该是这样:
import java.util.*;
import static java.lang.System.*;

public class X {

  public static void main(String[] args) throws Exception {
    final List<integer> list = 
             Arrays.asList(1, 2, 3, 4, 5, 6, 7);

    //sum
    int sum = 0;
    for(Integer v : list) {
      sum += v;
    }

    out.println("SUM = " + sum);

    //product
    long product = 1;
    for(Integer v : list) {
      product *= v;
    }

    out.println("PRODUCT = " + product);

    //print
    for(Integer v : list) {
      out.println(v);
    }


  }
}
如果用JavaScript以所谓闭包的形式处理,大概就是这样吧(只做sum部分):

var list = [1, 2, 3, 4, 5, 6, 7];

var total = 0;

list.forEach(function(element){
  total += element;
});

console.log(total);
从代码模块化的角度来说,采用一个function()来模块化计算的确起到一定的“打包”作用(不想说封装,因为封装有hide info的意味)。简单的for loop还是太自由了。这一点应该是可以理解的。


      • 抽象:
        • 闭包是数据和行为的组合,这使得闭包具有较好的抽象能力
          • 这个说法很象“面向对象编程”的说法:对象也是数据和行为的组合……不过对象包括了一系列的数据(闭包也有一系列)和一组行为(闭包似乎只有一个行为)

我尝试把原文中的代码转成JavaScript,大概就变成这个样子:
function make_stack() {
  var data = [];
  var last = -1;

  var push = function(e) {
      last++;
      data[last] = e;
    };

  var pop = function() {
      if(last == -1) {
        return null;
      }
      last--;
      return data[last + 1];
    };


  return {
      "push" : push,
      "pop"  : pop
  };
}

s = make_stack();

s = make_stack();

s.push("test0")
s.push("test1")
s.push("test2")
s.push("test3")

console.log(s.pop())
console.log(s.pop())
console.log(s.pop())

给我的感觉就是一种面向对象的写法。当然,这是闭包……

No comments: