淺談JavaScript 聲明提升
1 引例及基本原理
在學(xué)習(xí)JavaScript聲明提升之前,我們先看下面這個例子:
console.log(a); var a=2;
運行結(jié)果會是什么?你可能會有以下的猜測:
1.報錯ReferenceError: a is not defined;
2.打印2;
3.打印undefined。
正確的結(jié)果是第三種,打印undefined。
下面讓我們來看看具體的原因。其實,對于var a=2;這條語句,JavaScript會將其視為兩個聲明:
- 定義聲明var a,會在編譯階段進行;
- 賦值聲明a=2,會留在原地等待執(zhí)行階段進行。
而所謂的聲明提升:就是JavaScript會把var變量聲明和函數(shù)聲明都會被提升到各自作用域的頂部,而賦值操作并不會被提升。
因此,上面的例子實際是按照這樣的流程來處理:
var a; console.log(a); a=2;
我們還需要知道,不僅僅是var變量聲明會提升,函數(shù)聲明同樣也會提升,現(xiàn)在來看下面這個例子
foo(); function foo(){ console.log(a); var a=2; }
這個例子的運行結(jié)果為:打印undefined。這段代碼實際上會被理解為為下面的形式:
function foo(){ var a; console.log(a); a=2; } foo();
2 關(guān)于聲明提升的常見問題
2.1 函數(shù)表達式
先看一個函數(shù)表達式的例子:
console.log(foo); var foo=function(){}
上面代碼的運行結(jié)果為:打印undefined。實際上,變量標(biāo)識符foo被提升了,但它的賦值操作并沒有被提升,我們可以理解為下面的形式:
var foo; console.log(foo); foo=function(){}
結(jié)論:函數(shù)聲明會被提升,但函數(shù)表達式不會被提升。
2.2 聲明的優(yōu)先級
如果在同一個作用域內(nèi),存在同名的函數(shù)聲明和var變量聲明,那么會發(fā)生什么樣的情況呢?我們同樣再來看一個例子:
function a(){} var a; console.log(a);
var a; function a(){} console.log(a);
上面的兩種寫法,運行結(jié)果均為打印a(){}。也就是說,如果在同一個作用域內(nèi),存在同名的函數(shù)聲明和var變量聲明,則函數(shù)聲明的優(yōu)先級更高。
還有一種情況:如果同一個作用域內(nèi),存在多個同名的函數(shù)聲明。這種情況下,后面聲明的會覆蓋前面聲明的。
3 練習(xí)題
3.1 第一題
var getName = function() { console.log(1); } function getName() { console.log(2); } getName();
答案:打印1
解析:提升后的順序如下
var getName;//與函數(shù)聲明同名,故失效 function getName() { console.log(2); } getName = function() {//賦值 console.log(1); }; getName();
3.2 第二題
var a = 1; function b(){ a = 10; return; function a(){ console.log(a); } } b(); console.log(a);
答案:打印1
解析:首先,我們需要梳理清楚聲明的提升。
本題有幾個關(guān)鍵點,我們需要明白:
函數(shù)b內(nèi)的a函數(shù)雖然在return之后,但它并沒有失效,它會發(fā)生聲明提升,從而提升到b函數(shù)作用域的頂部。
很多童鞋(比如我TAT)可能會錯誤地認為這題的答案是10,認為我們在最后調(diào)用了b函數(shù),修改了全局變量a。實際上,由于函數(shù)a發(fā)生了聲明提升,導(dǎo)致在函數(shù)b內(nèi)“遮蔽”了全局作用域中的變量a,因此,a=10;其實是將函數(shù)a重新賦值。為了進一步測驗,大家可以把a函數(shù)注釋掉,會發(fā)現(xiàn)此時的答案就變成了10。
注:本題還涉及到了閉包的相關(guān)知識,這一題詳細的解析請見參考資料[2],講得非常詳細。
var a;//全局變量a發(fā)生了聲明提升 function b(){ function a(){//函數(shù)a發(fā)生聲明提升 console.log(a); } a = 10;//因為函數(shù)a離它最近,因此賦值給函數(shù)a return; } a = 1;//賦值給了全局變量a b(); console.log(a);
4 參考資料
[1] 《你不知道的JavaScript》
[2] js中變量名與函數(shù)名重名的問題,Charles_Tian
[3] 函數(shù)聲明與變量聲明的提升機制優(yōu)先級問題,一個菜鳥的奮斗史
以上就是淺談JavaScript 聲明提升的詳細內(nèi)容,更多關(guān)于JavaScript 聲明提升的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(一):棧
這篇文章主要介紹了JavaScript中數(shù)據(jù)結(jié)構(gòu)與算法(一):棧,本文講解了棧的結(jié)構(gòu)、什么是回文以及遞歸等內(nèi)容,講解的不錯,通俗易懂,需要的朋友可以參考下2015-06-06JavaScript實現(xiàn)輪播圖方法(邏輯清晰一看就懂)
這篇文章主要給大家介紹了關(guān)于JavaScript實現(xiàn)輪播圖方法的相關(guān)資料,JS輪播圖的實現(xiàn)核心是使用JavaScript來控制圖片的切換和顯示,配合HTML和CSS完成布局和樣式設(shè)置,文中介紹的方法邏輯清晰一看就懂,需要的朋友可以參考下2023-12-12JSON與JavaScript對象關(guān)系及語法規(guī)則詳解
這篇文章主要為大家介紹了JSON與JavaScript對象關(guān)系及語法規(guī)則詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06JavaScript移除數(shù)組內(nèi)重復(fù)元素的方法
這篇文章主要介紹了JavaScript移除數(shù)組內(nèi)重復(fù)元素的方法,實例分析了javascript遍歷數(shù)組及刪除等操作的相關(guān)技巧,需要的朋友可以參考下2015-03-03