ES6 --函数表达式和递归

这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

前言

今天复习ES6部分时,看见了函数表达式和递归部分,感受颇多,想和大家分享一下,函数声明和函数表达式要区分开哦,接下来就来谈一谈吧。

函数表达式

函数表达式虽然更强大,但也更容易让人迷惑。我们知道,定义函数有两种方式:函数声明和函数表达式。函数声明是这样的:\

 function functionName (arg0,arg1,arg2){
 //函数体函数声明的关键特点是函数声明提升,即函数声明会在代码执行之前获得定义。这意味着函数声明可以出现在调用它的代码之后:
 sayHi ();
 function sayHi (){ console . log (" Hi !");
复制代码

这个例子不会抛出错误,因为 JavaScript 引擎会先读取函数声明,然后再执行代码。 第二种创建函数的方式就是函数表达式。函数表达式有几种不同的形式,最常见的是这样的: let functionName = function (arg0,arg1,arg2){}函数表达式看起来就像一个普通的变量定义和赋值,即创建一个函数再把它赋值给一个变量 functionName 。这样创建的函数叫作匿名函数( anonymous funtion ),因为 function 关键字后面没有长识符。(匿名函数有也时候也被称为兰姆达函数)。未赋值给其他变量的匿名函数的 name 属性是空学符串。 函数表达式跟 JavaScript 中的其他表达式一样,需要先赋值再使用。下面的例子会导致错误: 

sayHi();1/Error! function doesn ' texist yet 
 let sayHi = function (){ console . log (" Hi !"); a 
复制代码

理解函数声明与函数表达式之间的区别,关键是理解提升。比如,以下代码的执行结果可能会出乎意料:\

//千万别这样做! 
if ( condition ){
 function sayHi (){ console . log (' Hi !');
) else {
 function sayHi (){ on console . log (' Yo !');
复制代码

这段代码看起来很正常,就是如果 condition 为 true ,则使用第一个 sayHi ()定义;否则,就使用第二个。事实上,这种写法在 ECAMScript 中不是有效的语法。 JavaScript 引擎会尝试将其纠正为适的声明。问题在于浏览器纠正这个问题的方式并不一致。多数浏览器会忽略 condition 直接返回第一个声明。 Firefox 会在 condition 为 true 时返回第一个声明。这种写法很危险,不要使用。不过,果把上面的函数声明换成函数表达式就没问题了:

//没问题 
 let sayHi ;
 if ( condition ){
 sayHi = function (){
 console . log (" Hi !");
}else { 
 sayHi = function () 
 console . log (" Yo !");
}

复制代码

这个例子可以如预期一样,根据 condition 的值为变量 sayHi 赋予相应的函数。创建函数并赋值给变量的能力也可以用于在一个函数中把另一个函数当作值返回:

 function createComparisonFunction ( propertyName )
 return function (object1,object2)(
 let value1=object1[ propertyName ]; 
 let value2=object2[ propertyName ]; 

 if (value1<value2){
 return -1; 
) else if ( valuel >value2){
return1;) else {
return 0;}
复制代码

这里的 createComparisonFunction ()函数返回一个匿名函数,这个匿名函数要么被赋值给一个变量,要么可以直接调用。但在 createComparisonFunction ()内部,那个函数是匿名的。任何时候,只要函数被当作值来使用,它就是一个函数表达式。本章后面会介绍,这并不是使用函数表达式的唯一方式。

递归函数通常的形式是一个函数通过名称调用自己,如下面的例子所示:

 function factorial ( num ){ 
 if ( num <=1){ 
return1; 
} else {
 return num * factorial ( num -1);
 }
复制代码

这是经典的递归阶乘函数。虽然这样写是可以的,但如果把这个函数赋值给其他变量,就会出问题:

 let anotherFactorial = factorial ;
 factorial = null ;
 console . log ( anotherFactorial (4));//报错
复制代码

这里把 factorial ()函数保存在了另一个变量 anotherFactorial 中,然后将 factorial 设置1nul1,于是只保留了一个对原始函数的引用。而在调用 anotherFactorial ()时,要递归调用actorial0),但因为它已经不是函数了,所以会出错。在写递归函数时使用 arguments . callee 可避免这个问题。  arguments . callee 就是一个指向正在执行的函数的指针,因此可以在函数内部递归调用,如下 :

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

复制代码

像这里加粗的这一行一样,把函数名称替换成 arguments . callee ,可以确保无论通过什么变量调用这个函数都不会出问题。因此在编写递归函数时, arguments . callee 是引用当前函数的首选。 不过,在严格模式下运行的代码是不能访问 arguments . callee 的,因为访问会出错。此时,可 以使用命名函数表达式( named function expression )达到目的。比如:

 const factorial =( function fo( num ){
 if ( num <=1于{ return 1;
 else {
 return Dumf ( num -1)
);
}

复制代码

这里创建了一个命名函数表达式 fo ,然后将它赋值给了变量 factorial 。即使把函数赋值给另一个变量,函数表达式的名称£也不变,因此递归调用不会有问题。这个模式在严格模式和非严格模式下都可以使用。

猜你喜欢

转载自juejin.im/post/7032636001071661092
今日推荐