先說說var和函式宣告

2022-08-23 20:39:07 字數 2623 閱讀 1926

變數提公升應該是var最引人矚目的乙個特點了。不說廢話,先上**。 

1 //code1:

2 a = 10

3var

a4 console.log(a)//105

6 //code2:

7var

a8 a = 10

9 console.log(a)//

10

聰明的你肯定都猜對了輸出結果。其實**1和**2是等價的。為什麼呢?關鍵就是變數提公升(hoisting)。對於用var宣告的變數,其宣告都會被提公升到作用域頂部。

來分析一下**1:

瀏覽器預編譯階段,瀏覽器找到宣告語句var a,建立變數a,初始化undefined。

瀏覽器執行階段,a = 10給a賦值10,然後列印。

所以,變數提公升其實就是宣告語句被提公升到作用域的頂部執行的一種現象。

ps:但如果有深入了解js執行機制的人肯定對這種說法是不解的。其實,所謂變數提公升不過是從表面上簡化地解釋了js的執行機制。實質上,在預編譯階段階段,瀏覽器會首先找到所有的變數和函式宣告,把變數初始化值為undefined(此處暫不考慮let和const宣告),函式宣告整體提公升(下面會講到)。然後瀏覽器再開始執行**,比如賦值,運算等等。所以,看起來就像變數的宣告被提公升到作用域頂部執行了一樣。不過所謂變數提公升也並沒有標準的定義,我所說的定義只是當下一種普遍的理解。不過對初學者來說,用變數提公升來理解var確實可能是一中比較好的做法,上來就提執行機制什麼的,那會嚇跑很多js的潛在愛好者吧。後面有機會的話也還會講講js的執行機制哦。

特別注意,函式作用域中用var宣告的變數在全域性作用域無法訪問到。例如:

console.log(a)

function c ()

}

先看**:

//code:1

console.log(a) // uncaught referenceerror: a is not defined

a = 3

//code:2

a = 3

console.log(a)//3

**1中編譯器會報錯,而2則會正常列印3。在1中a並沒有宣告,所以不會有變數提公升,所以列印a時顯示未定義。2中編譯器預編譯時沒找到任何變數宣告,執行時遇到未宣告的變數a,把其初始化為全域性變數,再進行賦值,表面上看起來與var a = 3並無什麼區別,但本質上還是不一樣的。

先上**

alert(a); // 彈出function a() function a()

function a()

和var宣告的變數一樣,函式宣告也存在提公升現象。也許你發現了不同:函式宣告是整體提公升的(alert中彈出的並不是undefined,而是整個函式整體),而var宣告的變數只是宣告提公升初始化為undefined。

接下來再看一段**:

foo();

function foo()

var foo = 2;

螢幕前的你是否感到有點懵逼?what?兩者都有變數提公升,那foo最後是函式還是變數?

答案是,還是函式,並且這段**會列印出foo。為什麼呢?如果現階段你還不想深究,那你可以暫時認為,函式宣告提公升優於變數提公升。

那如果在var foo = 2後列印foo,是函式還是2呢?答案是2。

事實上,在瀏覽器內部對**是這麼處理的:

預編譯階段,找到函式宣告和變數宣告,為其開闢記憶體空間。

再從頭開始執行**,比如函式呼叫和賦值等等操作。

在這段**裡面,瀏覽器在預編譯階段找到了函式foo的宣告,那麼會為foo開闢記憶體空間,然後對函式內部的宣告等等還會有一些操作。然後找到了變數foo的宣告,但由於foo已經存在記憶體空間中,所以不再為其開闢記憶體空間和初始化。

然後開始執行**,先呼叫函式,列印出了foo。接下來為foo賦值2,這時候foo由function變成了number。這時候如果再列印foo,就是2了。

很多人會問,如果**是下面這樣,結果會怎麼樣:

1

foo();23

var foo = 2;45

function

foo()

可能我會告訴你,這段**和上面那段**是等價的。並且如果你在最下面再添一行**,列印foo,結果仍是2。為什麼呢?因為函式宣告是整體提公升的,即便他的宣告在變數後,他的宣告依然會覆蓋上面變數的宣告,然而反過來變數宣告是無法覆蓋函式宣告的。如果對於初學者,從表面上看,那最好的理解就是認為函式宣告比變數宣告優先順序高。注意,我說的只是宣告哦。

下面這種情況屬於函式表示式,函式不會提公升

1 a() //

報錯: a is not a function23

var a = function

()

1 console.log(a) //

undefined23

var a = function

()

var lock = true

a()

//報錯:a is not a function

if(lock)

}else

}

上面說到函式宣告提公升時瀏覽器內部還會對函式進行一些操作,具體可以參考

JS中用var宣告變數和不用var宣告變數的區別

閱前須知 作用域 分為全域性和區域性 函式會開闢自己的作用域 或 空間 或 過程級 變數宣告 變數在指令碼中的第一次出現是在宣告中。變數在第一次用到時就設定於記憶體中,便於後來在指令碼中引用。使用變數之前先進行宣告。可以使用 var 關鍵字來進行變數宣告。var count 單個宣告。var cou...

函式宣告之function與var

紙上得來終覺淺,絕知此事要躬行。軟體這行業,很多東西還是要靠敲 敲出來的,你以為看書看的很通透,例子也能做出來的東西,一需要深入混合運用頓時覺得懵逼了。關鍵還是在於一知半解,不夠深入。今天我就總結一下近段時間遇到並糾結過的一些知識。老規矩,由淺入深,用發散性思維思考每個知識點。一 宣告乙個函式 fu...

let 和 const 宣告變數和常量 var

01 作用域只侷限於當前 塊 console.log str1 張三 console.log str2 無列印結果 02 使用let宣告的變數的作用域不會被提公升 03 在相同作用域下不能申明相同的變數 04 for迴圈體現let的父子作用域 var btns document.queryselec...