首页 > 代码库 > javascript函数及闭包详解

javascript函数及闭包详解

1.arguments[]对象在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。还可以用 arguments 对象检测函数的参数个数,引用属性 arguments.length

2function对象的length属性ECMAScript 定义的属性 length 声明了函数期望的参数个数

3Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法。这两个方法返回的都是函数的源代码,在调试时尤其有用

4闭包:

什么时候需要用到闭包:
1.需要在一个函数外部,访问函数内部的变量的时候(也就是说在函数运行完之后,你想要把变量保存下来,待需要的时候调用。而不是通过垃圾回收机制消除(garbage collection))。
2.保护变量安全。一个函数的内部变量,只能内部函数引用。

如何定义闭包:在一个函数内部,定义一个函数,并返回一个函数的引用。

3. 先看下闭包的两种形式:

//第一种形式:

function outer(){
       var i = 7;

       function inner(){

           alert(i);

       }

       inner();    //可以用setInteval(inner,5000);实现每5秒执行一次inner函数

}

 

//第二种形式:

function outer(){

       var i = 7;

       function inner(){

              alert(i);

       }

       return inner(); //函数是一种特殊的对象, 这里直接返回函数的引用

}

 var f = outer();       //使用f接受返回的内层函数的引用

f();  //调用内层函数

在第一种情况时: outer函数定义局部变量i, 函数inner(), 之后又调用了inner函数. 注意看inner()函数, inner函数中 并没有定义变量i, 这个i是来自于outer函数的局部变量. 当在inner函数被引用的时候, 由于内层的inner函数需要使用变量i, 因此这个运行时定义的变量i不能被释放, 从而在inner()函数执行时就可以取得这个变量的值.

 当第二种情况时: 执行outer()函数之后, 将返回inner()函数的引用, 由于外部变量f引用了内部函数inner(), 由于inner()函数同样需要使用变量i, 这个局部变量i也将被外部变量f所引用, 因此变量i依然不能被释放. 与第一种形式的区别是: 我们可以再outer()函数执行之后访问到变量i的值. 如果我们将alert(i); 改成 alert(++i); 那么在函数的外部, 我们执行f(); 此时变量i并没有释放, 结果应该是8, 如果再调用一次f(); 则结果变成9。但是: 如果我们再次调用outer();函数后将会创建一个新的局部变量, 之后再调用f(); 结果则变成了8. 也就是说只要外层函数没有再次创建新变量, 原来的变量i将一直有效.

4闭包可以用在许多地方。它的最大用处有两个,个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。


Js代码

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个

匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

4闭包的注意点:

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

5闭包的应用场景
保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。

  1. 在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
  2. 通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)
    私有属性和方法在Constructor外是无法被访问的

    function Constructor(...) {  
      var that = this;  
      var membername = value
      function membername(...) {...}
    }

以上3点是闭包最基本的应用场景,很多经典案例都源于此。

6Javascript的垃圾回收机制

在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。

 

javascript函数及闭包详解