从两个函数来学习js闭包的概念

来源:互联网 发布:qq酷双项淘宝客真的吗 编辑:程序博客网 时间:2024/05/19 19:41

从两个函数来学习js闭包的概念

1.闭包:闭包是指有权访问另一个函数作用域中的变量的函数。
如下面f1()函数,通过return将自己内部的函数f2()返回,使得在f1()的外部,可以通过return的f2()函数来访问f1()函数内部变量n

function f1() {  var n = 999;  nAdd = function() {    n += 1;  };  function f2() {    return n;  }  return f2;}var result1 = f1();var result2 = f1();alert(result1()); // 999nAdd();alert(result1()); // 1000alert(result2()); // 999

在继续闭包的理解之前,需要了解下函数执行过程中发生的一些事情:
当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。
然后,使用 arguments 和其他命名参数的值来初始化函数的活动对象(activation object)。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,……直至作为作用域链终点的全局执行环境。

也就是说:函数在执行之前,都会创建一个新的执行环境,从result2()的返回值999可以看出来,他并不受nAdd()操作的影响。
无论什么时候在函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量。一般来讲,
当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
但是,闭包的情况又有所不同。因为f1()return的函数f2包含了对f1函数内部定义的变量n的引用,所以变量n不会立即被回收。

下面这段函数执行结果为The Window

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

按照对闭包的初步了解,可能会认为执行object.getNameFunc()(),实际是在执行

function() {  return this.name;}

那么再从作用域链逐层向上寻找变量时,会找到object中的name
但是却找到了全局变量var name = “The Window”;
那么理解的误区在哪呢?就是对作用域链中具体保存的内容理解有误。
作用域链中保存的内容为:
对于每一个执行环境,都会创建一个与之关联的作用域链。每个执行环境的作用域链的前端,始终都是该执行环境的变量对象,对于全局执行环境就相当于window对象,对于函数执行环境就相当于该函数的活动对象;对于全局执行环境,已经是根部,没有后续,对于函数执行环境,其作用域链的后续是该函数对象的[[scope]]属性里的作用域链。
上面描述简单来说,就是函数执行过程中对于变量的查找是沿着作用域链逐层向上寻找,作用域链内存放是该作用域的活动变量,那么活动变量又包含哪些呢?
在一个函数对象被调用的时候,会创建一个活动对象,首先将该函数的每个形参和实参,都添加为该活动对象的属性和值;将该函数体内显示声明的变量和函数,也添加为该活动的的属性。
也就是说保存了形参和实参,函数体内显示声明的变量和函数。从上面可以看出并不包含this对象,所以并不会逐层向上寻找到object的this对象。

那么为什么又会把this指向window呢,其实执行的最终形式是:
object.getNameFunc()() --> getNameFunc() --> window.getNameFunc()
所以this指向函数的调用者window,最终this.name就指向了全局变量
var name = "The Window";

如有不正确的地方,欢迎交流指正。

相关参考:
http://www.cnblogs.com/amy-fox/p/5856771.html
http://www.cnblogs.com/pssp/p/5216085.html

原创粉丝点击