JavaScript中创建函数主要有两种方法:函数声明和函数表达式。这两种方式都有不同的适用场景。这篇笔记主要关注的是函数表达式的几大特点以及它的使用场景,下面一一描述。

主要特点

"htmlcode">

var sub = function(a1,a2){ 
  return a1-a2; 
} 

这个例子中函数表达式没有名称,属于匿名函数表达式。再看下面的例子:

var sub = function f(a1,a2){ 
  return a1-a2; 
} 
console.log(f(5,3));  //错误调用方式 
console.log(sub(5,3));  //正确调用方式 

在这个例子中,函数表达式的名称为f,这个名称f实际上变成了函数内部的一个局部变量,并且指代函数对象本身,在函数递归的时候有很大用处,后面会详细讲到。

"htmlcode">

console.log(add(1,2));  //"3" 
console.log(sub(5,3));  //"unexpected identifier",报错 
function add(a1,a2){ 
  return a1+a2; 
} 
var sub = function(a1,a2){ 
  return a1-a2; 
} 

第一条语句完全可以正常执行。对代码求值时,JavaScript引擎在第一遍就会声明函数并通过一个名为函数声明提升的过程将它们放到源代码树的顶部。也就是说在执行环境的创建阶段(函数被调用但还没有开始执行)就会对函数声明进行"hosting"操作。所以,即使声明函数的代码在调用它的代码后面,JavaScript引擎也会把函数声明提升到顶部。但是如果把函数声明更改为函数表达式,就会在执行期间报错。原因在于在执行到函数所在的语句之前,变量sub中并不会包含对函数的引用。也就是说在代码执行阶段,变量sub才会被赋值。除了以上不同,在其它方面函数声明和函数表达式的语法是等价的。

"htmlcode">

var sub = function f(a1,a2){ 
  console.log(typeof f); //"function" 
  return a1-a2; 
} 
console.log(typeof f);  //"Uncaught ReferenceError: f is not defined(…)" 

通过上面的例子可以看到,函数名称f只能在函数对象内部使用,函数表达式的函数名称并不存在于变量对象中。

使用场景

函数表达式的使用场景很多。下面主要描述的是函数递归以及代码模块化方面的应用。

"htmlcode">

function factorial(num){ 
  if(num <= 1){ 
     return 1; 
  }else{ 
     return num * factorial(num - 1); 
  } 
} 

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

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

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

function factorial(num){ 
  if(num <= 1){ 
     return 1; 
  }else{ 
     return num * arguments.callee(num - 1); 
  } 
} 

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

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

 "htmlcode">

var person = (function(){ 
  var _name = ""; 
  return{ 
    getName:function(){ 
       return _name; 
    }, 
    setName:function(newname){ 
       _name = newname; 
    } 
  }; 
}()); 
person.setName("John"); 
person.getName();  //"John"

 这个例子中创建了一个匿名函数表达式,这个函数表达式中包含了模块自身的私有变量和函数;这个函数表达式的执行结果返回一个对象,对象中包含了模块暴露给使用者的公共接口。代码模块化的具体形式还有很多,例如在一些常用的JavaScript库中通常都会使用类似下面例子的立即执行函数:

(function(){ 
  var _name = ""; 
  var root = this; 
  var person = { 
    getName: function(){ 
      return _name; 
    }, 
    setName: function(newname){ 
      _name = newname; 
    } 
  }; 
  root.person = person; 
}.call(this)); 
person.setName("John"); 
person.getName();  //"John"

 这种方式直接将包含模块公共接口的对象作为全局对象的一个属性,这样在其它地方直接可以使用全局对象的这个属性来使用这个模块了。

以上这篇老生常谈JavaScript 函数表达式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

标签:
javascript函数表达式

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
评论“老生常谈JavaScript 函数表达式”
暂无“老生常谈JavaScript 函数表达式”评论...

P70系列延期,华为新旗舰将在下月发布

3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。

而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?

根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。