溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中變量提升與預編譯的示例分析

發(fā)布時間:2021-03-02 10:12:54 來源:億速云 閱讀:145 作者:清風 欄目:web開發(fā)

這篇文章主要為大家展示了JavaScript中變量提升與預編譯的示例分析,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶大家一起來研究并學習一下“JavaScript中變量提升與預編譯的示例分析”這篇文章吧。

Java的特點有哪些

Java的特點有哪些 1.Java語言作為靜態(tài)面向對象編程語言的代表,實現(xiàn)了面向對象理論,允許程序員以優(yōu)雅的思維方式進行復雜的編程。 2.Java具有簡單性、面向對象、分布式、安全性、平臺獨立與可移植性、動態(tài)性等特點。 3.使用Java可以編寫桌面應用程序、Web應用程序、分布式系統(tǒng)和嵌入式系統(tǒng)應用程序等。

一、有趣的現(xiàn)象

按照大家的常識,JavaScript代碼在執(zhí)行是一定是自上而下的,你需要輸出一個字符串,當然需要提前聲明一個保存string類型的變量。如果深奧的道理我都能懂,于是我閱讀了下面的代碼。

1.1 我以為的開局
var str = '123';console.log(str); // 123

我們調換一下代碼的位置在再看:

console.log(str); // undefinedvar str = '123';

我好像找到規(guī)律了!!!

當我看完了前兩段代碼并且進行了“深度思考”后,我好像找到規(guī)律了,那就是:在當前代碼塊后函數(shù)中,在變量聲明和初始化之前使用變量,會拿不到正確的值。

1.2 實際上是這樣的

帶著上面的“結論”我來到了這里

var val = '余光';(function(){
    console.log(val); // 余光})();

果然如此!,在變量聲明和初始化之后耶穌也阻擋不了我拿到val的值,我說的?。。?/p>

當我看到下面一段代碼時,我已經產生了動搖,此事必要蹊蹺。

var val = '余光';(function(){
    console.log(val); // undefined
    var val = '測試';})();

Ps:如果大家立即執(zhí)行函數(shù)存在疑問,不妨看看《JavaScript之深入理解立即調用函數(shù)表達式(IIFE)》吧~

這…我慫了,是什么原因導致這樣的現(xiàn)象發(fā)生的呢?Js又是如果處理的呢?

二、Js的預解析

在當前的作用域內,無論在哪里變量聲明,在幕后,都會進行一次看不見的移動。

注意:僅聲明被“移動”。即聲明和賦值在某些時候被動分開了。而這次看不見的移動實際上就是Js在編譯階段的解析。

來看一段《你知不知道的Js》中經典的例子:

name = '余光'; // 未添加關鍵字(未聲明),name為全局變量,,即window.name = '余光'var name; // 再次聲明name,此時name未進行初始化,它的值是undefined嗎?console.log(name); // ?

結果是成功打印“余光”,這樣看不見的移動就發(fā)生在Js預解析(編譯)之中。

2.1 核心:預解析

為了搞明白這個核心問題,我們需要回顧一下,引擎會在解釋JavaScript代碼之前首先對其進行編譯。編譯階段中的一部分工作就是找到所有的聲明,并用合適的作用域將它們關聯(lián)起來。感興趣的小伙伴可以閱讀《JavaScript中的變量對象》和《從作用域到作用域鏈》這兩篇文章哦~

因此,發(fā)生這樣的事情,包括變量函數(shù)在內的所有聲明都會在任何代碼被執(zhí)行前首先被處理。當你看到var a = 2;時,可能會認為這是一個聲明。但JavaScript實際上會將其看成兩個聲明:var a;和a = 2;。

  • 第一個定義聲明是在編譯階段進行的。

  • 第二個賦值聲明會被留在原地等待執(zhí)行階段。

即代碼是這樣寫的:

// 我們看到的代碼:var name = '余光';

但Js會將它解析成:

// 聲明(Declaration)var name; // 聲明但未初始化,所以分配 undefined// 初始化(Initialization)name = '余光'; // 初始化(賦值)

所以本小結的一段代碼應該這樣分析:

var name; // 聲明name提到作用域頂部,并被分配了一個undefinedname = '余光'; // 進行初始化操作console.log(name); // '余光'
2.2 注意:只有聲明被提升了

只有聲明會被提升,而賦值和其他代碼邏輯會在執(zhí)行到代碼的位置時才會生效。所以會有下面的問題:

foo();function foo(){
    console.log(name); // undefined
    var name = '余光';}

函數(shù)被提升了,自然可以正常執(zhí)行,但變量僅僅是聲明被提升了。

2.3 每個作用域都會進行提升操作

還是上面的代碼:

foo();function foo(){
    console.log(name); // undefined
    var name = '余光';}

實際它在編譯時是這樣的:

function foo(){
    var name; // 聲明
    console.log(name); // undefined
    name = '余光'; // 初始化}foo(); // 函數(shù)執(zhí)行

三、提升之間的優(yōu)先級

既然我們知道了變量函數(shù)會被提升,他們之間又是如何判斷優(yōu)先級的呢?

3.1 函數(shù)會被首先提升,然后才是變量

我們分析下面的代碼:

foo();var foo; // 1function foo(){
    console.log('余光');}foo = function(){
    console.log('小李');}

本著函數(shù)優(yōu)先提升的原則,他會被解析成這樣:

function foo(){
    console.log('余光');}foo(); // 余光foo = function(){
    console.log('小李');}

注意,var foo 因為是一個重復聲明,且優(yōu)先級低于函數(shù)聲明所以它被忽略掉了。

3.2 函數(shù)字面量不會進行函數(shù)提升

最直觀的例子,就是在函數(shù)字面量前調用該函數(shù):

foo();var foo = function(){
    console.log(1);}// TypeError: foo is not a function

這段程序中:

  1. 變量標識符foo被提升并分配給所在作用域(在這里是全局作用域),因此在執(zhí)行foo()時不會導致ReferenceError(),而是會提示你 foo is not a function。

  2. 然后就是執(zhí)行foo,foo此時并沒有賦值(注意變量被提升了)。由于對undefined值進行函數(shù)調用而導致非法操作,因此拋出TypeError異常。

四、ES6和小結

ES6新增了兩個命令letconst,用來聲明變量,有關它們完整的概念我會在《ES6基礎系列》中總結,提起它們,是因為變量提升在它們身上不會存在。

4.1 變量提升是可以規(guī)避的

let命令改變了語法行為,它所聲明的變量一定要在聲明后使用,否則報錯。

// var 的情況console.log(foo); // 輸出undefinedvar foo = 2;// let 的情況console.log(bar); // 報錯ReferenceErrorlet bar = 2;

上面代碼中,變量foo用var命令聲明,會發(fā)生變量提升,即腳本開始運行時,變量foo已經存在了,但是沒有值,所以會輸出undefined。變量bar用let命令聲明,不會發(fā)生變量提升。這表示在聲明它之前,變量bar是不存在的,這時如果用到它,就會拋出一個錯誤。

在變量提升上,const和let一樣,只在聲明所在的塊級作用域內有效,也不會變量提升

4.2 小結
  1. 變量提升:函數(shù)聲明和變量聲明總是會被解釋器悄悄地被"提升"到方法體的最頂部,但變量的初始化不會提升;

  2. 函數(shù)提升:函數(shù)聲明可以被看作是函數(shù)的整體被提升到了代碼的頂部,但函數(shù)字面量表達式并不會引發(fā)函數(shù)提升;

  3. 函數(shù)提升優(yōu)先與變量提升;

  4. let和const可以有效的規(guī)避變量提升

最后提煉一下:JavaScript引擎并不總是按照代碼的順序來進行解析。在編譯階段,無論作用域中的聲明出現(xiàn)在什么地方,都將在代碼本身被執(zhí)行前首先進行處理,這個過程被稱為提升。聲明本身會被提升,而包括函數(shù)表達式的賦值在內的賦值操作并不會提升。

以上就是關于“JavaScript中變量提升與預編譯的示例分析”的內容,如果改文章對你有所幫助并覺得寫得不錯,勞請分享給你的好友一起學習新知識,若想了解更多相關知識內容,請多多關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI