目錄
。如果深奧的道理我都能懂,於是我閱讀了下面的程式碼。
就發生在Js預解析(編譯)之中。
所以本小結的一段程式碼應該這樣分析:
函數被提升了,自然可以正常執行,但變數只是宣告被提升了。
3.1 函数会被首先提升,然后才是变量
3.2 函数字面量不会进行函数提升
4.1 变量提升是可以规避的
4.2 小结
首頁 web前端 js教程 JavaScript專題之一:變數提升與預編譯

JavaScript專題之一:變數提升與預編譯

Mar 02, 2021 am 09:42 AM
javascript

JavaScript專題之一:變數提升與預編譯

目錄

  • #前言
  • 一、有趣的現象
  • 二、Js的預解析
  • 三、提升之間的優先權
  • 四、ES6
  • 寫在最後

##(相關免費學習推薦:

javascript影片教學

#前言

    本篇文章是《JavaScript專案進階系列》的第一篇文章,全系列大概會包含例如:
  • 防抖節流
  • #深淺拷貝
  • 數組去重
  • 排序

等等經典的專案知識點。取名為專案進階是因為它們在許多場合的「出鏡率高」很高,為了避免化身

google內容搜尋師

,《JavaScript專案進階系列》誕生了! ! ! JavaScript專題之一:變數提升與預編譯

一、有趣的現象

#依照大家的常識,JavaScript程式碼在執行是一定是自上而下的,你需要輸出一個字串,當然需要事先宣告一個

保存string類型的變數
。如果深奧的道理我都能懂,於是我閱讀了下面的程式碼。

1.1 我以為的開局

var str = '123';console.log(str); // 123
登入後複製

我們調換程式碼的位置在再看:

console.log(str); // undefinedvar str = '123';
登入後複製

我好像找到規律了!!!

#當我看完了前兩段程式碼並且進行了「深度思考」後,我好像找到規律了,那就是:在當前程式碼區塊後函數中,在變數宣告和初始化

之前

使用變量,會拿不到正確的值。 JavaScript專題之一:變數提升與預編譯

1.2 其實是這樣的

帶著上面的「結論」我來到了這裡

var val = '余光';(function(){
    console.log(val); // 余光})();
登入後複製
果然如此! ,在

變數宣告和初始化之後

耶穌也阻擋不了我拿到val的值,我說的! ! !

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

var val = '余光';(function(){
    console.log(val); // undefined
    var val = '测试';})();
登入後複製

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

這…我慫了,是什麼原因導致這樣的現象發生的呢? Js又是如果處理的呢? JavaScript專題之一:變數提升與預編譯

二、Js的預解析

在目前的作用域內,無論在哪裡變數聲明,在幕後,都會進行一次看不見的移動。 注意:僅宣告被「移動」。即聲明和賦值在某些時候被動分開了。而這次看不見的移動其實就是

Js在編譯階段的解析

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

name = '余光'; // 未添加关键字(未声明),name为全局变量,,即window.name = '余光'var name; // 再次声明name,此时name未进行初始化,它的值是undefined吗?console.log(name); // ?
登入後複製
結果是成功打印“余光”,這樣

看不見的移動
就發生在Js預解析(編譯)之中。

2.1 核心:預解析

為了搞清楚這個核心問題,我們需要回顧一下,引擎會在解釋JavaScript程式碼之前先將其編譯。編譯階段中的一部分工作就是找到所有的聲明,並用適當的作用域將它們關聯起來。有興趣的小夥伴可以閱讀《JavaScript中的變數物件》和《從作用域到作用域鏈》這兩篇文章哦~因此,發生這樣的事情,包括變數函數在內的所有宣告都會在任何程式碼被執行前先被處理。當你看到

var a = 2
    ;時,可能會認為這是一個宣告。但JavaScript實際上會將其看成兩個聲明:var a;和a = 2;。
  • 第一個定義宣告是在編譯階段進行的。
第二個賦值宣告會被留在原地等待執行階段。

即程式碼是這樣寫的:

// 我们看到的代码:var name = '余光';
登入後複製

但Js會將它解析成:

// 声明(Declaration)var name; // 声明但未初始化,所以分配 undefined// 初始化(Initialization)name = '余光'; // 初始化(赋值)
登入後複製
所以本小結的一段程式碼應該這樣分析:
var name; // 声明name提到作用域顶部,并被分配了一个undefinedname = '余光'; // 进行初始化操作console.log(name); // '余光'
登入後複製

2.2 注意:只有宣告被提升了

只有宣告會被提升,而賦值和其他程式碼邏輯會在執行到程式碼的位置時才會生效

。所以會有下面的問題:

foo();function foo(){
    console.log(name); // undefined
    var name = '余光';}
登入後複製
登入後複製
函數被提升了,自然可以正常執行,但變數只是宣告被提升了。

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

還是上面的程式碼:

foo();function foo(){
    console.log(name); // undefined
    var name = '余光';}
登入後複製
登入後複製

實際上它在編譯時是這樣的:JavaScript專題之一:變數提升與預編譯

function foo(){
    var name; // 声明
    console.log(name); // undefined
    name = '余光'; // 初始化}foo(); // 函数执行
登入後複製

三、提升之間的優先權

既然我們知道了變數

函數###會被提升,他們之間又是如何判斷優先順序的呢? ###
3.1 函数会被首先提升,然后才是变量

我们分析下面的代码:

foo();var foo; // 1function foo(){
    console.log('余光');}foo = function(){
    console.log('小李');}
登入後複製

本着函数优先提升的原则,他会被解析成这样:

function foo(){
    console.log('余光');}foo(); // 余光foo = function(){
    console.log('小李');}
登入後複製

注意,var foo 因为是一个重复声明,且优先级低于函数声明所以它被忽略掉了。

3.2 函数字面量不会进行函数提升

最直观的例子,就是在函数字面量前调用该函数:

foo();var foo = function(){
    console.log(1);}// TypeError: foo is not a function
登入後複製

这段程序中:

  1. 变量标识符foo被提升并分配给所在作用域(在这里是全局作用域),因此在执行foo()时不会导致ReferenceError(),而是会提示你 foo is not a function
  2. 然后就是执行foo,foo此时并没有赋值(注意变量被提升了)。由于对undefined值进行函数调用而导致非法操作,因此抛出TypeError异常。

四、ES6和小结

ES6新增了两个命令letconst,用来声明变量,有关它们完整的概念我会在《ES6基础系列》中总结,提起它们,是因为变量提升在它们身上不会存在

4.1 变量提升是可以规避的

let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

// var 的情况console.log(foo); // 输出undefinedvar foo = 2;// let 的情况console.log(bar); // 报错ReferenceErrorlet bar = 2;
登入後複製

上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。变量bar用let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

在变量提升上,const和let一样,只在声明所在的块级作用域内有效,也不会变量提升

4.2 小结
  1. 变量提升:函数声明和变量声明总是会被解释器悄悄地被"提升"到方法体的最顶部,但变量的初始化不会提升;
  2. 函数提升:函数声明可以被看作是函数的整体被提升到了代码的顶部,但函数字面量表达式并不会引发函数提升;
  3. 函数提升优先与变量提升;
  4. let和const可以有效的规避变量提升

最后提炼一下:JavaScript引擎并不总是按照代码的顺序来进行解析。在编译阶段,无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,这个过程被称为提升。声明本身会被提升,而包括函数表达式的赋值在内的赋值操作并不会提升。

相关免费学习推荐:javascript(视频)

以上是JavaScript專題之一:變數提升與預編譯的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

See all articles