首頁  >  文章  >  web前端  >  淺談javascript 函數表達式和函數宣告的差異_javascript技巧

淺談javascript 函數表達式和函數宣告的差異_javascript技巧

WBOY
WBOY原創
2016-05-16 15:21:501239瀏覽

javascript中宣告函數的方法有兩種:函數宣告式和函數表達式.

區別如下:

1).以函數宣告的方法定義的函數,函數名是必須的,而函數表達式的函數名是可選的.

2).以函數宣告的方法定義的函數,函數可以在函數宣告之前呼叫,而函數表達式的函數只能在宣告之後呼叫.

3).以函數聲明的方法定義的函數並不是真正的聲明,它們僅僅可以出現在全局中,或者嵌套在其他的函數中,但是它們不能出現在循環,條件或者try/catch/ finally中,而

    函數表達式可以在任何地方宣告.

以下分別用兩種方法定義函數:

 //函数声明式
 function greeting(){
    console.log("hello world"); 
 }
 
 
 //函数表达式
 var greeting = function(){
   console.log("hello world"); 
 }

下面一個有趣的javascript:

function f() { console.log('I am outside!'); }
(function () {
 if(false) {
  // 重复声明一次函数f
  function f() { console.log('I am inside!'); }
 }
 f();
}());

會輸出什麼呢?第一個反應應該是"I am outside"吧.  結果在chrome中輸出"I am inside",IE11直接報錯,firefox低一點的版本輸出"I am outside"...

chrome輸出的結果很明確的反應了用函數宣告式宣告的函數的特性--函數在宣告之前就可以呼叫.

IE報錯顯示缺少物件,因為函數宣告在了條件裡,違反了函數宣告式的原則.

函數表達式的作用域:

如果函數表達式宣告的函數有函數名稱,那麼這個函數名稱就相當於這個函數的一個局部變數,只能在函數內部呼叫,舉個栗子:

var f = function fact(x) { 
        if (x <= 1) 
          return 1;
        else 
          return x*fact(x-1);
        };
        alert(fact());  // Uncaught ReferenceError: fact is not defined

fact()在函數內部可以呼叫,在函數外部呼叫就會報錯:fact未定義.
fact

我們再來詳細看下

函數宣告

  函數宣告範例程式碼

程式碼如下:

function fn () {
  console.log('fn 函数执行..');
  // code..
}

  這樣我們就聲明了一個名稱為fn的函數,這裡出個思考,你認為在這個函數的上面來呼叫他的話會執行嗎?還是會報錯?

程式碼如下:fn(); // 在先前呼叫我們宣告的fn函數 function fn () { console.log('fn 函數執行..'); // code..}

  控制台輸出結果:

  是的,此時fn函數是可以被呼叫的,這裡來總結下原因。

總結:

  1:此時fn函數是變數的結果,預設儲存在全域上下文的變數中(可用 window.函數名稱 來驗證)

  2:此方式為函數聲明,在進入全域上下文階段創建,程式碼執行階段,它們已經可用。 ps:javaScript每次進入方法時都會先初始化上下文環境(由全域 → 局部)

  3:它可以影響變數物件(僅影響儲存在上下文中的變數)

函數表達式

  函數表達式範例程式碼

程式碼如下:

var fn = function () {
  console.log('fn 函数【表达式】声明执行..')
  // code..
}

  這樣我們就聲明了一個匿名函數,並且把它的引用指向了變數fn

  再次在該表達式宣告的函數上下方各呼叫一次,來看控制台的輸出結果。

程式碼如下:

// 为了清晰的看到控制台的输出,我们在各自调用前后做个标记,增加可读性。
console.log('之前调用开始..');
fn();
console.log('之前调用结束..');
var fn = function () {
  console.log('fn 函数【表达式】声明执行..')
  // code..
}
console.log('之后调用开始..');
fn();
console.log('之后调用开始..');

  控制台列印結果:

  可以看到程式碼執行到第一次呼叫fn()函數的時候,提示:fn is not a function (fn 不是一個方法),遇到錯誤而終止運行。

  這說明在第一次呼叫fn()的同時,var fn 變數並沒有做為全域物件的一個屬性而存在,且 fn 所引用的匿名函數上下文也沒有被初始化,所以在他之前呼叫失敗。

程式碼如下:

// 现在先把之前的调用逻辑给注释掉,再看下控制台的输出
//  console.log('之前调用开始..');
//  fn();
//  console.log('之前调用结束..');
  var fn = function () {
    console.log('fn 函数【表达式】声明执行..')
    // code..
  }
  console.log('之后调用开始..');
  fn(); // 在表达式之后调用
  console.log('之后调用开始..');

  控制台列印結果:

  可以看出,在該表達式函數之後來呼叫是可以的,來總結下那是為什麼呢?

總結:

  1:首先變數本身不做為一個函數存在,而是一個匿名函數的參考(值類型的不屬於引用)

  2:在程式碼執行階段,初始化全域上下文時,它沒有被做為全域的一個屬性而存在,所以不會造成變數物件的污染

  3:此類型的聲明一般在插件的開發較常見,也可做為閉包中回呼函數的呼叫

  所以 function fn () {} 不等於 var fn = function () {} ,他們有本質上的差別。

以上就是本文的全部內容了,思路很清晰,對比也很明確,是篇非常不錯的文章,小夥伴們一定要仔細研讀下

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn