摘要:但是碰到聲明提升,這種想法就會被打破。聲明一個函數進行相應的操作,會得到函數聲明提升的結果。由此可以發現變量和函數的聲明都會被提升在其他代碼的前面執行。一個普通塊內部的函數聲明通常會被提升到所在的作用域的頂部。的創建初始化和賦值均會被提升。
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的創建、初始化和賦值均會被提升。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102824.html
摘要:代碼在執行時并不完全是由上到下一行一行執行的,由此產生了一個提升的問題。第二個賦值聲明會被留在原地等待執行階段。可以得知函數聲明提升的優先權大于普通變量聲明。 JavaScript代碼在執行時并不完全是由上到下一行一行執行的,由此產生了一個提升的問題。 什么是提升 可以簡單理解為:聲明(變量和函數)都會被移動到各自作用域的最頂端,這個過程被稱為提升。 具體例子看提升 下面兩個例子a會l...
摘要:輸出的結果為輸出的結果為提升后輸出的結果為重新定義了變量輸出的結果為如果定義了相同的函數變量聲明,后定義的聲明會覆蓋掉先前的聲明,看如下代碼輸出練習的值是多少的值是多少第二題的解析請看這里參考資料文章文章中文版鏈接文章推薦文章變量提升 JavaScript 變量聲明提升 原文鏈接 一個小例子 先來看個例子: console.log(a); // undefined var a =...
摘要:有意思的是,這意味著變量在聲明之前甚至已經可用。的這個特性被非正式地稱為聲明提前,即函數里聲明的所有變量但不涉及賦值都被提前至函數體的頂部。但實際上會將其看成兩個聲明和。第二個賦值聲明會被留在原地等待執行階段。 簡介 JavaScript的函數作用域是指在函數內聲明的所有變量在函數體內始終是可見的。有意思的是,這意味著變量在聲明之前甚至已經可用。JavaScript的這個特性被非正式地...
摘要:函數和變量相比,會被優先提升。這意味著函數會被提升到更靠前的位置。僅提升聲明,而不提升初始化。 JavaScript 函數高級——執行上下文與執行上下文棧(圖解+典型實例分析) 變量提升與函數提升 變量聲明提升 通過 var 定義(聲明)的變量,在定義語句之前就可以訪問到 值:undefined /* 面試題 : 輸出 undefined */ var a = 3 ...
摘要:變量提升需要注意兩點提升的部分只是變量聲明,賦值語句和可執行的代碼邏輯還保持在原地不動提升只是將變量聲明提升到變量所在的變量范圍的頂端,并不是提升到全局范圍,說明如下會輸出變量提升之后的效果函數聲明會提升,但是函數表達式就不了。 問題 有些朋友可能會覺得javascript的代碼是從上到下,一行一行的解釋執行的。如果按照這樣的思路,在有些情況下閱讀代碼會得到錯誤的結果,考慮以下代碼: ...
閱讀 455·2023-04-25 23:00
閱讀 3486·2021-11-22 13:54
閱讀 1885·2021-10-27 14:14
閱讀 1478·2019-08-30 13:59
閱讀 3503·2019-08-23 16:15
閱讀 1948·2019-08-23 16:06
閱讀 3315·2019-08-23 15:26
閱讀 1246·2019-08-23 13:48