函數表達式和函數聲明

函數表達式和函數聲明

在ECMAScript中,建立函數的最經常使用的兩個方法是函數表達式和函數聲明,二者期間的區別是有點暈,由於ECMA規範只明確了一點:函數聲明必須帶有標示符(Identifier)(就是你們常說的函數名稱),而函數表達式則能夠省略這個標示符:函數

  函數聲明:spa

  function 函數名稱 (參數:可選){ 函數體 }調試

  函數表達式:code

  var name=function 函數名稱(可選)(參數:可選){ 函數體 }blog

因此,能夠看出,若是不聲明函數名稱,它確定是表達式,可若是聲明瞭函數名稱的話,如何判斷是函數聲明仍是函數表達式呢?ECMAScript是經過上下文來區分的,若是function foo(){}是做爲賦值表達式的一部分的話,那它就是一個函數表達式,若是function foo(){}被包含在一個函數體內,或者位於程序的最頂部的話,那它就是一個函數聲明。遞歸

  function foo(){} // 聲明,由於它是程序的一部分
var bar = function foo(){}; // 表達式,由於它是賦值表達式的一部分

new function bar(){}; // 表達式,由於它是new表達式

(function(){
function bar(){} // 聲明,由於它是函數體的一部分
})();

還有一種函數表達式不太常見,就是被括號括住的(function foo(){}),他是表達式的緣由是由於括號 ()是一個分組操做符,它的內部只能包含表達式,咱們來看幾個例子:ip

  function foo(){} // 函數聲明
(function foo(){}); // 函數表達式:包含在分組操做符內

命名函數表達式

提到命名函數表達式,理所固然,就是它得有名字,前面的例子var bar = function foo(){};就是一個有效的命名函數表達式,但有一點須要記住:這個名字只在新定義的函數做用域內有效,由於規範規定了標示符不能在外圍的做用域內有效:作用域

  var f = function foo(){
return typeof foo; // foo是在內部做用域內有效
};
// foo在外部用因而不可見的
console.log(typeof foo); // "undefined"
console.log(f()); // "function"

   var f = function foo(){
   return foo; // foo是在內部做用域內有效
   };
    // foo在外部用因而不可見的
   console.log(typeof foo); // "undefined"
   console.log( f()==f); // "function"
   console.log(f.name);//fooio

   var f=function g(){
   return 23;
   }
   console.log( typeof g);//undefined
   console.log(g());//Uncaught ReferenceError: g is not defined
   console.log( g);//Uncaught ReferenceError: g is not defined
   console.log(f);//function g()
   console.log(f());//23
   console.log(f.name);//gconsole

  最後補充一下,函數的遞歸通常都是用arguments.callee()的方法,但在嚴格模式下會出錯,這是就能夠用命函數表達式來達成相同的結果

  用arguments.callee():

var sum = function(n){
  if (n <= 1) return 1;
  else return n+arguments.callee(n - 1)
}
var sum1=sum; //sum1和指向sum指向同一個引用
sum=function(){
return 0;
}
console.log(sum1(5));//15
console.log(sum(5));//0 sum指向另外一個函數引用

用命名函數表達式的方法:

    var f = function foo(m){
      if(m<=1){
      return 1;
     }    
      else{return m*foo(m-1)}     // foo是在內部做用域內有效,這裏能夠用m*f(m-1)
  };
                        
    console.log(f(4));            // foo在外部用因而不可見的,故只能用f()

 既然,這麼要求,那命名函數表達式到底有啥用啊?爲啥要取名?

 正如咱們開頭所說:給它一個名字就是可讓調試過程更方便,由於在調試的時候,若是在調用棧中的每一個項都有本身的名字來描述,那麼調試過程就太爽了,感覺不同嘛。

相關文章
相關標籤/搜索