也聊聊Javascript闭包(Closure)

来源:互联网 发布:bt天堂软件下载 编辑:程序博客网 时间:2024/05/19 22:01

说起闭包,记忆最深刻的莫过于初中数学老师的解释,一个包含边界的数值范围。一条数轴,两个实心点,一条括号一样的线,表示了闭包。对应的数学记号例如[1,8],包含1、8以及大于1小于8的所有数。网上有些资深人士说,Javascript的闭包就是内部函数,或者更具体点是return的内部函数。作为数学系的毕业生,直觉告诉我应该没有那么简单:

  1. 中学和大学的数学课程里面都有涉及到闭包,但都是范围概念。
  2. 如果闭包是指内部函数,那么就完全没有必要引入闭包那么个抽象的概念害人,应该直接叫内部函数。

打开Google,输入javascript closure,选择前三个搜索结果,开始研究。

  • Stackoverflow
    感觉流于展示javascript闭包如何工作,没有找到期待的定义和工作原理。
  • 阮一峰的网络日志
    阮大侠学识渊博,有很多的粉丝。我对大侠也很钦佩,但是对于javascript闭包这篇文章里面的一些内容 不大认同,用他的例子执行出的结果也与预期不一致。
  • http://jibbering.com/
    详细、深入,最重要的是看到了我一直期待的范围(scope)。文章很长,但是值得精读。我对于javascript闭包的理解 主要基于该文。

最重要的概念——执行上下文(Execution Context)

我更愿意把它称为执行环境,感觉这个叫法更接地气,容易理解,下面都以执行环境来称呼它。

所有的代码都需要在某个执行环境里面才能执行,执行环境可以被理解为一个存储key-value的对象。javascript里面常用的有两类执行环境, 全局环境(Global)和函数(Function)环境。每次执行一个函数(Function),当前执行环境就会切换到一个新的执行环境,如果函数里面再调另外函数,会形成执行环境栈(Stack)。全局环境存储两类内容,全局变量和全局的函数。函数环境存储三类内容,参数(Arguments)、局部变量(Local Varibale)、所有子函数。

子函数的执行环境是父函数所形成的函数环境,也就是他能够访问父函数的参数、父函数的局部变量、同级别的其它子函数。执行环境,或者叫可访问范围,才是真正的闭包。函数的执行需要执行环境,函数还存活的时候(比如return回去),它的执行环境不能被垃圾回收器回收,否则函数无法执行。闭包的魔法正在于此。

同级别的其它子函数作为执行环境例子

function func1(){function func2(){console.log("Exe func2");}return function(){func2();}}    func1()();

func2作为return函数的执行环境,返回之后依然存在。

阮大侠的两个例子解释

阮大侠在那篇文章里面提供了两个例子,我尝试用执行环境来解释一下。我的运行环境是Node.js,只是把alert换做console.log而已。代码如下:

var name = "The Window";  var object = {    name: "My Object",getNameFunc: function() {      return function() {        return this.name;      };    }  };  console.log(object.getNameFunc()());var name = "The Window";  var object = {    name: "My Object",    getNameFunc: function() {      var that = this;      return function() {        return that.name;      };    }  };console.log(object.getNameFunc()());

执行结果为:
undefined
My Object

我想换一下代码书写方式,但语义不变:

var name = "The Window";  function Object1() {this.name = "My Object";this.getNameFunc = function() {return function() {return this.name;}}}var obj1 = new Object1();console.log(obj1.getNameFunc()());function Object2() {this.name = "My Object";this.getNameFunc = function() {var that = this;return function() {return that.name;}}}var obj2 = new Object2();console.log(obj2.getNameFunc()());

  • 关于Object1
    Object1为一个构造函数,getNameFunc为Object1的一个对象方法,getNameFunc没有参数,没有局部变量,没有除最内层返回函数之外的子函数。 所以最内层函数的执行环境为{}, 最内层函数内的this指向global,Node.js里面全局变量不会自动赋值给global,所以结果为undefined,浏览器环境 下应该为The Window。
  • 关于Object2
    Object2为一个构造函数,getNameFunc为Object2的一个对象方法,getNameFunc有一个局部变量that,this是obj2,所以that为obj2,最内层函数 的执行环境为{that:{name:"My Object"}}。执行结果自然就是My Object。

区别就是执行环境不同。

结语

推荐英文好的朋友好好看看这篇文章,http://jibbering.com/。长但值得拥有。

6 0
原创粉丝点击