關於JS函數與變量提升,一文說清楚

刀法如飛 發佈 2022-06-29T17:03:56.796107+00:00

JS語言非常靈活,因其獨特魅力受到大家的追捧。一開始人們覺得JS很簡單,同時也會覺得都不像程序語言。當深入使用過後,才會發覺設計者無心插柳的妙處。函數預處理,函數聲明時會提前,並做好預處理,函數名賦值和確定作用域的範圍以上代碼片段中foo調用在函數foo聲明之前,這是沒問題的。

JS語言非常靈活,因其獨特魅力受到大家的追捧。一開始人們覺得JS很簡單,同時也會覺得都不像程序語言。當深入使用過後,才會發覺設計者無心插柳的妙處。

函數預處理,函數聲明時會提前,並做好預處理,函數名賦值和確定作用域的範圍

以上代碼片段中foo調用在函數foo聲明之前,這是沒問題的。原因是function會提前進行預處理,js引擎在詞法解析時會建立一個foo變量,賦值為foo函數,同時確定函數的作用域。

其中var 聲明的a變量雖然提升了,但是並沒有賦值,因此a此時為undefined。如果採用let或者const聲明則不會提升,提前調用則會報錯。所以,js中最好別用var聲明,而是採用let或const。

函數提升時賦值是會受作用域影響,因為es6之後引入了塊級作用域

以上代碼片段,foo函數變量也會提升,但是因為作用域問題並不會賦值,因此列印時undefined,而執行時報錯。如果是es5環境,則沒有塊級作用域,那麼foo()提前調用也是合法的。

注意塊級作用域下函數變量聲明和賦值是分開的,只要調用在後面,雖然不在同一個作用域下也沒問題。


賦值在運行時執行,這裡if是false,因此並未賦值,從而放在後面調用時也會報錯。


JS作用域分為全局作用域與函數級作用域兩級,外部不能訪問內容,函數可以嵌套,通過作用域鏈函數內部可以逐級向上訪問查找變量,直到全局作用域。注意塊級只是區隔,與函數作用域作為層級概念並不相同。

strict嚴格模式下的函數提升與作用域


在嚴格模式下,函數變量聲明也不提升了,還得嚴格遵循塊級作用域。

總結

  1. 函數名也是一個變量,也會提升。函數還會提前預處理,賦值和確定作用域,因此函數調用在前也可以正常訪問。
  2. 在塊級作用域下,函數會跨級提升,會確定作用域,但是不會賦值。只有塊被執行後才會賦值。函數作用域下的子函數名只會提升至父函數,不會超過父函數的作用域。
  3. strict模式下,若函數不在塊內則會提升且賦值,若在塊內則因為非var聲明就不會提前,直接訪問報錯。

以上對於熟悉JS的來說可能比較好懂,對於熟悉Java和C語言的人來講可能會徹底懵圈。編程的有趣在於,不同的語言有不同的特點,當你掌握各種程式語言時,就像見證了各地風俗人情,思路會變得非常開闊。

關鍵字: