自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解Javascript 函數(shù)聲明和函數(shù)表達式的區(qū)別

開發(fā) 開發(fā)工具
通過Javascript函數(shù)可以讓JS具有面向?qū)ο蟮囊恍┨卣?,實現(xiàn)封裝、繼承等,也可以讓代碼得到復用。但事物都有兩面性,Javascript函數(shù)有的時候也比較“任性”,你如果不了解它的“性情”,它很可能給你制造出一些意想不到的麻煩出來。

Javascript Function無處不在,而且功能強大!通過Javascript函數(shù)可以讓JS具有面向?qū)ο蟮囊恍┨卣?,實現(xiàn)封裝、繼承等,也可以讓代碼得到復用。但事物都有兩面性,Javascript函數(shù)有的時候也比較“任性”,你如果不了解它的“性情”,它很可能給你制造出一些意想不到的麻煩(bugs)出來。

Javascript Function有兩種類型:

1)函數(shù)聲明(Function Declaration);

  1. // 函數(shù)聲明 
  2. function funDeclaration(type){         
  3.     return type==="Declaration"; 

2)函數(shù)表達式(Function Expression)。

  1. // 函數(shù)表達式 
  2. var funExpression = function(type){        
  3.     return type==="Expression"; 

上面的代碼看起來很類似,感覺也沒什么太大差別。但實際上,Javascript函數(shù)上的一個“陷阱”就體現(xiàn)在Javascript兩種類型的函數(shù)定義上。下面看兩段代碼(分別標記為代碼1段和代碼2段):

  1. funDeclaration("Declaration");//=> true 
  2. function funDeclaration(type){        
  3.     return type==="Declaration"; 
  1.  funExpression("Expression");//=>error var funExpression = function(type){          
  2.      return type==="Expression"; 

用函數(shù)聲明創(chuàng)建的函數(shù)funDeclaration可以在funDeclaration定義之前就進行調(diào)用;而用函數(shù)表達式創(chuàng)建的funExpression函數(shù)不能在funExpression被賦值之前進行調(diào)用。為什么會這樣呢?!這就要理解Javascript Function兩種類型的區(qū)別:用函數(shù)聲明創(chuàng)建的函數(shù)可以在函數(shù)解析后調(diào)用(解析時進行等邏輯處理);而用函數(shù)表達式創(chuàng)建的函數(shù)是在運行時進行賦值,且要等到表達式賦值完成后才能調(diào)用。這個區(qū)別看似微小,但在某些情況下確實是一個難以發(fā)現(xiàn)的陷阱。出現(xiàn)這個陷阱的本質(zhì)原因體現(xiàn)在這兩種類型在Javascript function hoisting(函數(shù)提升)和運行時機(解析時/運行時)上的差異。上面兩段代碼的函數(shù)提升可示意為下圖:

代碼1段JS函數(shù)等同于:

  1. function funDeclaration(type){         
  2.     return type==="Declaration"; 
  3. funDeclaration("Declaration");//=> true 

代碼2段JS函數(shù)等同于:

  1. var funExpression; 
  2. funExpression("Expression");//==>error 
  3. funExpression = function(type){         
  4.     return type==="Expression"; 

上述代碼在運行時,只定義了funExpression變量,但值為undefined。因此不能在undefined上進行函數(shù)調(diào)用。此時funExpression賦值語句還沒執(zhí)行到。為了進一步加深JS函數(shù)兩種類型的區(qū)別,下面給出一個更具迷惑性的示例,請看下面的代碼(代碼段4):

  1. var sayHello;     
  2. console.log(typeof (sayHey));//=>function    console.log(typeof (sayHo));//=>undefinedif (true) {         
  3.     function sayHey() {             
  4.         console.log("sayHey"); 
  5.     } 
  6.     sayHello = function sayHo() {             
  7.         console.log("sayHello"); 
  8.     } 
  9. } else {         
  10.    function sayHey() {             
  11.    console.log("sayHey2"); 
  12.   sayHello = function sayHo() {             
  13.    console.log("sayHello2"); 
  14. }     
  15. sayHey();// => sayHey2    sayHello();// => sayHello 

分析:sayHey是用函數(shù)聲明創(chuàng)建的,在JS解析時JS編譯器將函數(shù)定義進行了函數(shù)提升,也就是說,在解析JS代碼的時候,JS編譯器(條件判斷不形成新的作用域,兩個sayHey函數(shù)定義都被提升到條件判斷之外)檢測到作用域內(nèi)有兩個同名的sayHey定義,***個定義先被提升,第二個定義接著被提升(第二個定義在***個定義之下),第二個定義覆蓋了***個sayHey定義,所以sayHey()輸出sayHey2;而sayHello是用函數(shù)表達式創(chuàng)建的,其表達式的內(nèi)容是在JS運行時(不是解析時)才能確定(這里條件判斷就起到作用了),所以sayHello表達式執(zhí)行了***個函數(shù)定義并賦值,則sayHello()輸出sayHello。

代碼段4的代碼實際上等同于下面的代碼(代碼段5):

  1. var sayHello;     
  2. function sayHey() {             
  3.     console.log("sayHey"); 
  4. }     
  5. function sayHey() {             
  6.     console.log("sayHey2"); 
  7. }     
  8. console.log(typeof (sayHey));//=>function     
  9. console.log(typeof (sayHo));//=>undefined 
  10. if (true) {        //hoisting... 
  11.     sayHello = function sayHo() {             
  12.         console.log("sayHello"); 
  13.     } 
  14. } else {        //hoisting... 
  15.         sayHello = function sayHo() {             
  16.             console.log("sayHello2"); 
  17.         } 
  18.     }     
  19.     sayHey();// => sayHey2     
  20.     sayHello();// => sayHello 

有的人也許會懷疑函數(shù)sayHey的定義是第二個覆蓋***個了么?我們可以把sayHey的源代碼進行輸出,有圖有真相,如下圖所示:

總結(jié)

Javascript 中函數(shù)聲明和函數(shù)表達式是存在區(qū)別的,函數(shù)聲明在JS解析時進行函數(shù)提升,因此在同一個作用域內(nèi),不管函數(shù)聲明在哪里定義,該函數(shù)都可以進行調(diào)用。而函數(shù)表達式的值是在JS運行時確定,并且在表達式賦值完成后,該函數(shù)才能調(diào)用。這個微小的區(qū)別,可能會導致JS代碼出現(xiàn)意想不到的bug,讓你陷入莫名的陷阱中。

***附上代碼段4中sayHello和sayHey兩個函數(shù)的核心步驟(個人理解,若有異議歡迎留言探討):

sayHello函數(shù)執(zhí)行的主要步驟示意圖

上圖為sayHello函數(shù)執(zhí)行的主要步驟示意圖。

sayHey函數(shù)執(zhí)行主要步驟的示意圖

上圖為sayHey函數(shù)執(zhí)行主要步驟的示意圖。

【本文為51CTO專欄作者“謝軍”的原創(chuàng)稿件,轉(zhuǎn)載可通過作者微信公眾號(jingfeng18)獲取聯(lián)系】

戳這里,看該作者更多好文

責任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2011-05-30 16:11:46

Javascript

2025-03-12 08:45:15

函數(shù)聲明函數(shù)表達式IIFE

2021-06-28 08:01:57

JS 函數(shù)表達式函數(shù)聲明

2010-11-16 14:53:02

Oracle游標表達式

2009-10-12 10:11:08

Lambda表達式編寫

2023-11-02 18:45:00

Rust編程表達式

2010-09-10 15:20:11

SQL函數(shù)計算表達式

2020-10-16 06:40:25

C++匿名函數(shù)

2009-08-31 17:11:37

Lambda表達式

2022-01-04 19:21:04

函數(shù)TypeScript重載

2012-04-28 15:22:46

PHP

2021-08-31 07:19:41

Lambda表達式C#

2024-12-02 10:56:29

2009-08-10 10:06:10

.NET Lambda

2011-05-11 17:40:30

PHP正則表達式

2009-09-16 09:58:53

PHP正則表達式函數(shù)

2009-09-16 10:43:22

PHP正則表達式函數(shù)

2022-05-26 08:53:47

Go函數(shù)代碼

2021-08-07 07:21:26

AndroidKotlinLambda

2010-10-08 09:17:07

JavaScript表JavaScript運
點贊
收藏

51CTO技術(shù)棧公眾號