首页 > 其他 > 详细

函数表达式

时间:2017-10-11 19:42:39      阅读:135      评论:0      收藏:0      [点我收藏+]

JavaScript中创建函数主要有两种方法:函数声明和函数表达式。这两种方式都有不同的适用场景。这里主要介绍函数表达式的应用场景。

1.函数递归:是在一个函数通过调用名字调用自身的情况下构成的

看下面的例子:

1
2
3
4
5
6
7
function factorial(num){
    if(num <= 1){
         return 1;
    }else{
         return num * factorial(num - 1);
    }
}

  这是一个经典的阶乘函数,但是这个例子存在的一个问题是函数名称factorial与函数体紧密耦合在一起,执行下面的语句就会报错:

1
2
3
var anotherFactorial = factorial;
factorial = null;
console.log(anotherFactorial(5));   //"Uncaught TypeError: factorial is not a function"

  报错的原因在于在函数体内部会调用factorial函数,而变量factorial对函数的引用已经被解除所以报错。这种情况的解决方法一般可以使用arguments.callee来解决,arguments.callee始终指向当前的函数,例如:

1
2
3
4
5
6
7
function factorial(num){
    if(num <= 1){
         return 1;
    }else{
         return num * arguments.callee(num - 1);
    }
}

  这样在此执行anotherFactorial函数就可以得到正确结果了。但是在严格模式"strict"下,arguments.callee是不能通过脚本访问的,这是就可以使用函数表达式来解决这个问题了,例如:

1
2
3
4
5
6
7
8
var factorial = (function f(num){
    if(num <= 1){
         return 1;
    }else{
         return num * f(num - 1);
    }
});
console.log(factorial(5));   //"120"

 

2.闭包:是指有权访问另一个函数作用域中的变量的函数

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,可以在函数外部对函数内部的局部变量进行操作。

闭包耗费内存的原因:闭包作用域链引用了外部函数的变量对象,闭包没有执行完毕,作用域链引用的外部函数的变量对象都不会被回收,闭包中不需要使用的变量尽早解除引用

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

闭包在访问外部变量、this、引用HTML元素的时候需要注意:
1.闭包只能取得包含函数中任何变量的最后一个值
2.如果闭包的外部环境是一个函数,那么闭包中的this事window,如果闭包的外部环境是object,那么this是这个对象
3.闭包在引用HTML元素时,一旦HTML元素被引用,那么该元素将无法被销毁(内存泄露)

闭包的应用场景:自执行函数、私有属性和方法

3.模仿块级作用域:JavaScript中是没有块级作用域概念的。也就是说,在块级语句中定义的变量,实际上是在包含函数中(外部函数)而非语句中创建的。
1
2
3
4
5
6
function outputNumber(count){
  for(var i=0;i<1000;i++){
    alert(i);
  }
  alert(i);  //count
}

该函数在java、C#等语言中,变量i只会在for循环语句中有定义,循环结束,i也就被销毁了。但在JavaScript中,变量i是定义在outputNumber()活动对象中的,因此在它定义开始,就可以在函数内部访问它。即使重新声明同一个变量,也不会改变它的值。

匿名函数可以用来模仿块级作用域并避免这个问题,用作块级作用域(也称私有作用域)的匿名函数的语法如下:

1
2
3
(function(){
   //这是块级作用域
})()

以上代码定义变调用了一个匿名函数,将函数声明包含在一个小括号里面,表示它是个函数表达式。紧跟其后的另一对小括号会立即调用这个函数。

 

http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

 

函数表达式

原文:http://www.cnblogs.com/crbluesky/p/7652312.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!