JavaScript闭包

  1. 特殊的变量作用域
    js变量的作用域有:全局变量和局部变量。函数内部可以直接读取全局变量,函数外部无法读取函数内的局部变量。
    在函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上是通过隐式声明了一个全局变量。

  2. 外部如何读取局部变量
    有时候需要在得到函数内的局部变量,正常情况下是办不到的,所以必须变通实现。那就是在函数内部再定义一个函数。

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

函数f2包含在函数f1内部,这时f1内部的所有局部变量对f2都是可见的,但是f2内部的局部变量对f1是不可见的。
子对象会一级一级地向上寻找父对象的变量,父对象的所有变量,对子对象都是可见的,反之不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,不就可以在f1的外部读取它的内部变量了吗?

function f1(){
    n=999;
    function f2(){
    alert(n); 
   }
    return f2;
}
var result = f1();
result(); //999
  1. 闭包的概念
    闭包就是能够访问其它函数内部变量的函数。
    闭包实际上是将函数内部和函数外部连接在一起的桥梁。
  2. 闭包的作用
  • 可以读取函数内部的变量
  • 让这些变量的值始终保存在内存中
function f1(){
    n=999;
    nadd = function(){ n += 1; }   //全局变量
    function f2(){
    alert(n); 
   }
    return f2;
}
var result = f1();
result(); //999
nadd();
result(); //1000

result其实就是闭包函数f2, 两次执行结果不同,证明f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
原因:f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后被垃圾回收机制回收。

  1. 常见陷阱
function createFunctions(){
  var result = new Array();
  for (var i=0; i<10; i++){
    result[i] = function(){
      return i;
    };
  }
  return result;
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
  console.log(funcs[i]());
}

你以为输出0~9,结果输出10个10
分析:陷阱在于函数带()才执行。
上述代码的执行过程是:

var result = new Array(), i;  //变量声明提升hoisting
result[0] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
result[1] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
...
result[9] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
i = 10;
funcs = result;
result = null;

console.log(i); // funcs[0]()就是执行 return i 语句,就是返回10
console.log(i); // funcs[1]()就是执行 return i 语句,就是返回10
...
console.log(i); // funcs[9]()就是执行 return i 语句,就是返回10

只有result被回收了,i 没有被回收,因为 i 还在被function引用着。

  1. 作用域链
    作用域链是单向的,全局window是最大的作用域,全局里声明的函数是次一级的作用域,这样的函数里面可以访问到全局里的各种变量和函数,但在全局中访问不到这个函数里面的函数和变量;这样次一级里面的函数是再次一级,它同样也是可以访问上一级和全局的函数与变量,而上级访问不到这个里面的东西,这样一层一层的递进,就形成了作用域链。

你可能感兴趣的:(JavaScript闭包)