首頁 >web前端 >js教程 >javascript聲明提升的介紹(附範例)

javascript聲明提升的介紹(附範例)

不言
不言轉載
2019-03-22 09:39:471938瀏覽

這篇文章帶給大家的內容是關於javascript聲明提升的介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Javascript宣告提升

在分析宣告提升之前,我認為有必要知道的兩點:

一、引擎查詢變數的兩種方式

引擎查詢變數的方式可以分為LHS和RHS兩種方式,透過「L」和「R」是可以大致了解意思,分別是賦值操作的左側和右側。 (不能光是理解為「=」的左右側可不行,因為賦值操作的形式有多種。)

#簡單說下我對這兩種查詢方式的理解:
LHS:賦值操作的目標是誰。 (查詢變數)
RHS:誰是賦值運算的源頭。 (查詢變數的值)

這樣說可能有些難以理解,舉個栗子:

function foo(a){
    //这里存在一个隐式变量分配,LHS查询变量a,并赋值2.
    //隐式a = 2;
    //左边LHS查询变量b,查询作用域中是否存在b这个变量。
    //右边RHS查询变量a的值,将a赋值给b。
    var b = a;
    //返回a,b是RHS查询变量a的值和变量b的值并使用。
    return a + b;
}
//左边LHS查询变量c,查询作用域中是否存在c这个变量。
//右边RHS引用函数foo,将2作为参数传进去。
var c = foo(2);

二、異常

關於異常要強調一點,必須在嚴格模式下。因為在非嚴格模式下,LHS查詢若是在最頂層的全域作用域上找不到查詢的變量,則會建立一個該名稱變數返還給引擎。

ReferenceError:同作用域判別失敗相關。 (例如:作用域中遍尋不到所需的變數)
TypeError:作用域判別成功了,但是對結果的操作是非法或不合理的。 (例如:試圖對一個非函數類型的值進行函數調用,或引用null或undefined類型的值中的屬性)

舉個栗子:

"strict"
function foo() {
    console.log(a) //undefined
    console.log(b) //ReferenceError
}
var a = 2;

聲明提升

#一、初步了解

寫javascript程式碼時,很多時候都會覺得程式碼會自上而下的執行。但是碰到聲明提升,這種想法就會被打破。

舉個栗子:

a = 2;
var a;
console.log(a);

运行结果为: 2

如果按照常理的自上而下執行,那麼a執行的預期結果應當是undefined,然而為什麼會是2?
這就是宣告提升的結果。

二、進一步了解

當初步了解聲明提升的時候,碰上下面的程式碼:

console.log(a);
var a = 2;

运行结果为:undefined

初步了解聲明提升之後,會自然而然的認為,聲明就會被提升,然而宣告的時候賦值,卻得不到變數的值。

其實,上面程式碼的運行步驟可以分解為:

var a; //声明提升
console.log(a); //打印a的值
a = 2; //对a进行赋值

原來,宣告提升就是字面上的宣告提升,其餘的操作(如:賦值和其他邏輯)都還在原地踏步。

宣告一個函數進行對應的操作,會得到函數宣告提升的結果。由此可以發現:變數和函數的宣告都會被提昇在其他程式碼的前面執行。

三、逐步了解

透過幾個試驗可以逐步了解到,其實宣告提升就是:變數和函數的宣告會被提昇在其他程式碼(目前作用域)的前面執行。

走到這裡,有人就會想到,要是函數表達式,也會進行提升嗎?

答案是:不會。而且,即使是具名函數表達式,在名稱識別碼賦值之前也是不能使用的。

舉個栗子:

foo(); //TypeError
bar(); //ReferenceError
var foo = function bar(){};

程式碼分解為:

var foo; //变量声明提升
foo(); //foo对undefined值进行函数调用导致非法操作,故TypeError
bar(); //bar函数并没有声明,故ReferenceError
foo = function bar(){}; //对foo进行赋值

所以:函數表達式在名稱識別碼賦值之前是不能使用的。

注意:1、每個作用域都會進行提升操作。 (所以函數內部形成的作用域也會有提升操作,提升           運算只限於目前的函數內部作用域)
##2、在函數與變數提升時,函數優先提升。
3、一個普通區塊內部的函數宣告通常會被提升到所在的作用域的頂端。

四、深入了解

在閱讀《你不知道的javascript》時,學習let的過程中,會發現有說明提到:使用let進行的聲明不會在作用域中進行提升。聲明的程式碼在被運行之前是,聲明並不存在。

舉個栗子:

console.log(a);
let a = 2;

运行结果是:ReferenceError: Cannot access 'a' before initialization. //初始化前无法访问"a"
然後回到之前我執行的程式碼,將let換為var,回傳的結果是undefined。

二者結合,再加上閱讀我花了兩個月的時間才理解let這篇文章,發現對let是否提升有了一個更新的認識。

作者把js變數分成三個部分運算:

建立(create)、初始化(initialize)和賦值(assign)

上面的操作之所以會有不同的回應並不是說let沒有創建,而是有一個初始化的過程並沒有執行。而

在初始化之前使用變數,就會形成一個暫時性死區

經過var和let和function的測試可以總結到:

var的創建和初始化被提升,賦值不會被提升。

let的創建被提升,初始化和賦值不會被提升。

function的建立、初始化和賦值都會被提升。

這篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的JavaScript教學影片專欄!

#

以上是javascript聲明提升的介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除