Js 變量聲明提升和函數聲明提升


Js代碼分為兩個階段:編譯階段和執行階段

Js代碼的編譯階段會找到所有的聲明,並用合適的作用域將它們關聯起來,這是詞法作用域的核心內容

包括變量聲明(var a)和函數聲明(function a(){})在內的所有聲明都會在代碼被執行前的編譯階段首先被處理

 

過程就好像變量聲明和函數聲明從他們代碼中出現的位置被移動到執行環境的頂部,這個過程就叫做提升

只有聲明操作會被提升,賦值和邏輯操作會被留在原地等待執行

 

變量聲明

Js編譯器會把變量聲明看成兩個部分分別是聲明操作(var a)和賦值操作(a=2)

聲明操作在編譯階段進行,聲明操作會被提升到執行環境的頂部,值是undefined(表示未初始化)

賦值操作會被留在原地等待執行階段

 1 var a = 2;
 2 
 3 function foo() {
 4     console.log(a); //undefined
 5     var a = 10;
 6     console.log(a); //10
 7 }
 8 
 9 foo();
10 
11 // 相當於
12 
13 var a = 2;
14 
15 function foo() {
16     var a;
17     console.log(a); //undefined
18     a = 10;
19     console.log(a); //10
20 }
21 
22 foo();

函數聲明

定義函數有兩種方式:函數聲明和函數表達式

函數聲明提升會在編譯階段把聲明和函數體整體都提前到執行環境頂部,所以我們可以在函數聲明之前調用這個函數

函數表達式,其實就是變量聲明的一種,聲明操作會被提升到執行環境頂部,並賦值undefined。賦值操作被留在原地等到執行。

1 // 函數聲明
2 
3 foo(); //100
4 
5 function foo(){
6     console.log(100);
7 }
 1 // 函數表達式
 2 baz(); // TypeError: baz is not a function
 3 
 4 var baz = function(){
 5     console.log(200);
 6 }
 7 
 8 //相當於
 9 
10 var baz;
11 
12 baz();
13 
14 baz = function() {
15     console.log(200);
16 };

 

控制語句

Js中使用函數級作用域,不存在塊級作用域。所有普通塊中的聲明都會被提升到頂部,所以控制語句對聲明的控制就顯得完全沒有效果

 1 if (false) {
 2     var a = 10;
 3 }
 4 
 5 console.log(a); //undefined
 6 
 7 // 相當於
 8 
 9 var a;
10 if (false) {
11     a = 10;
12 }
13 
14 console.log(a) //undefined

 

奇怪的函數聲明

1 console.log(a); //undefined
2 
3 if (false) {
4     function a() {
5         console.log(100);
6     }
7 }
8 
9 a(); //TypeError: a is not a function 理論上應該是100

奇怪吧??函數提升發生在所有代碼執行之前,所以盡管a函數的定義過程寫在了if分支中,但是理論上,它是不會影響函數聲明提升的

在新版本的瀏覽器中會出現此問題,舊版本的瀏覽器中會在控制台中打印出100

這也提醒了我們盡量不要在控制語句中進行聲明,會造成很多無法預知的bug

 

函數優先

提升操作會優先進行函數的聲明

函數會首先被提升然后才是變量,重復的變量聲明會被忽略,只剩下賦值操作,多個函數聲明可以進行覆蓋

聲明的順序是這樣的:

1. 找到所有的函數聲明,初始化函數體,如有同名的函數則會進行覆蓋

2. 查找變量聲明,初始化為undefined,如果已經存在同名的變量,就什么也不做直接略過

 

 1 // 1
 2 foo(); //200
 3 
 4 function foo() {
 5     console.log(100);
 6 }
 7 
 8 function foo() {
 9     console.log(200);
10 }
11 
12 // 2
13 console.log(foo); //function foo(){...}
14 
15 function foo(){
16     console.log(200);
17 }
18 var foo = 100;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM