js闭包

关于闭包:
闭包,是指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

i.函数的定义:
函数的作用域是在定义函数时候就已经确定,而不是在执行的时候确定。

ii.Javascript中的变量查找机制
变量的访问:
当在函数b中访问一个变量的时候,搜索顺序是:
先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依次查找,直到找到为止。
如果函数b存在prototype原型对象,则在查找完自身的活动对象后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。如果整个作用域链上都无法找到,则返回undefined。

iii.函数从定义到执行的流程
当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。
当执行函数a的时候,a会进入相应的执行环境(excution context)。
在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。
然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。
下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。
最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。
到此,整个函数a从定义到执行的步骤就完成了

1.闭包的形式

function f1(){
  var n=999;
  function f2(){
    alert(n); // 999
  }
}

2.闭包的作用:
2.1.从函数外访问函数的局部变量
使得函数外能访问函数内的变量

function f1() {  
    var n = 999;    
    function f2() {      
        alert(n);    
    }    
    return f2;  
}  
var result = f1();  
result(); // 999

函数内部的方法可以访问函数的变量,通过返回一个这个内部方法的引用在外部来访问函数的变量.

function f(x) { 
  var g = function () { return x; }
  return g;
}
var h = f(1);
alert(h()); 

归根结底:
函数的作用域是在定义函数(而非声明时)时候就已经确定的,而不是在执行的时候确定。即h函数的作用域是在定义时候确定的,即h指向的那个匿名函数在定义的时候已经确定了作用域。
2.2.保留闭包所属函数的变量值在内存中

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

变量值在内存中导致内存消耗很大,所以不能滥用闭包。在IE中可能导致内存泄漏。
2.3.避免命名空间污染

var a = 4;
(function(){
  var a = 5;
  console.log(a);//5  
})();
console.log(a); //4

总结:
函数变量的访问、函数的引用决定了闭包的功能

注:函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量.

参考文章:
1.javascript深入理解js闭包

此条目发表在JavaScript分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注