javascript 闭包内部机制

在初学JavaScript函数式编程的时候,经常会出现令人出乎意料的结果,而原因,大都是由于不理解JavaScript闭包引起的;理解JavaScript的闭包,可以从JavaScript的闭包内部机制出发。

函数:

function creatFunctions() {
  var result = [];
  for (var i = 0; i < 10; i++) {
    result[i] = function () {
      return i
    };
  }
  return result;
};
console.log(creatFunctions())

结果:

0: function creatFunctions/result[i]()
1: function creatFunctions/result[i]()
2: function creatFunctions/result[i]()
3: function creatFunctions/result[i]()
4: function creatFunctions/result[i]()
5: function creatFunctions/result[i]()
6: function creatFunctions/result[i]()
7: function creatFunctions/result[i]()
8: function creatFunctions/result[i]()
9: function creatFunctions/result[i]()

这个函数会返回一组数组,应该每个函数都应该返回对应的值;而出现结果的原因就在于闭包不是立即执行的。

1、闭包的概念

JavaScript高设中,闭包是指有权访问另一个函数作用域的中的变量的函数,创建闭包的形式,就是在函数的内部创建另一个函数。

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();//MDN

displayName就是一个闭包。

2、闭包的内部机制

闭包的内部机制在于理解作用域链,函数的执行环境,变量对象和活动对象;

函数被调用时会创建一个执行环境,在执行环境中初始化该函数的活动对象、变量对象、和作用域链。其中,作用域链是指向当前执行环境可访问的变量对象的指针,是一个由内而外的过程。以上述函数为例;

由于所有函数的执行环境底层都是在全局执行环境中,JavaScript在运行时,首先初始化活动对象,即函数自带的arguments、this变量;全局变量makeFunc、myFunc会绑定到变量对象上;该执行环境初始化之后会推入栈中,此后会初始化函数makeFunc的局部变量,读取局部变量'name';内部函数displayName的函数声明;值得注意的是,每个执行环境的内部属性[[scope]] 保存当前执行环境可访问的变量对象,由内而外,即内部函数始终可以访问外部函数直到全局环境的所有变量,而外部环境是无法读取内部函数变量对象的;这是由于作用域链中定义的。

一般函数在执行完成后,会销毁其执行环境,只保留全局执行环境中变量;但是在闭包中,由于闭包并不是立即执行,而是保存着内部函数执行需要的所有变量,包括内部变量和外部变量;在需要时再执行;函数执行完毕后;由于内部匿名函数的作用于链依然引用这个活动对象;因此活动对象仍然会保存在内存中。

3、闭包的缺陷

闭包只是对函数内部的活动对象的保留,JavaScript中对变量只能保存一个定义;即 i 只能保存一个值,也就是上例中 i=10;闭包不是立即执行,当闭包执行时;向上搜索函数用到的所有变量,而内存中保存的是最后一次i的值;因此 i=10;

闭包会引用包含它函数的作用域,因此比普通函数占用更多的内存。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章