JavaScript變量的作用域介紹

JavaScript變量的作用域介紹

JavaScript 變量的作用域決定了變量在代碼中的可訪問性。

var 是 JavaScript 中最早用于聲明變量的關鍵字,它函數作用域或全局作用域。

let 關鍵字,具有塊級作用域、全局作用域。

const關鍵字,具有塊級作用域、全局作用域。

var、let 和 const 關鍵字對比表

特性

var

let

const

作用域

函數作用域或全局作用域

塊級作用域、全局作用域

塊級作用域、全局作用域

變量提升

提升到作用域頂部,初始化為?undefined

聲明前訪問會報錯,因存在“暫時性死區”(Temporal Dead Zone)

聲明前訪問會報錯,因存在“暫時性死區”(Temporal Dead Zone)

重復聲明

合法,后續聲明覆蓋前一個值

不合法,拋出?SyntaxError

不合法,拋出?SyntaxError

是否可變

可變

可變

不可變(引用不可變,但內容可變)

是否成為全局對象屬性

是(在全局上下文中)

下面展開介紹

1.?作用域類型

全局作用域(Global Scope

  • 定義:在函數外聲明的變量。
  • 特點
    • 任何地方都可訪問,包括函數內部。過度使用全局變量可能導致命名沖突和代碼難以維護。
    • 在瀏覽器環境中,全局變量通常與 window 對象關聯。
    • 瀏覽器環境中,var?聲明的全局變量會成為?window?對象(在瀏覽器環境中)的屬性,let?和?const?不會。
  • 注意

避免隱式全局變量,始終顯式聲明變量。

在非嚴格模式下,未使用 var、let 或 const 關鍵字聲明的變量會被隱式提升為全局變量。

在嚴格模式下,未聲明的變量會導致 ReferenceError,因此不會創建隱式全局變量。

var:在全局上下文中聲明的變量會成為全局對象的屬性,具有全局作用域。

let 和 const:在全局上下文中聲明的變量是全局變量,但不會成為全局對象的屬性;?let 或 const 關鍵字還可以聲明塊級作用域(見后面)。

  • 全局變量的創建方式:?

1)隱式全局變量:

myGlobalVar = "Hello, World!"; // 隱式全局變量
console.log(myGlobalVar); // 輸出 "Hello, World!"
console.log(window.myGlobalVar); // 輸出 "Hello, World!",因為它是 window 的屬性

2)顯式全局變量:

使用window對象可以明確地創建全局變量。

window.myExplicitGlobalVar = "Hello, again!"; // 顯式全局變量
console.log(window.myExplicitGlobalVar); // 輸出 "Hello, again!"
console.log(myExplicitGlobalVar); // 輸出 "Hello, again!",直接訪問也可以。

3) 使用 var、let 或 const 關鍵字聲明全局變量

//使用 var 聲明全局變量
var globalVar = "Hello";
console.log(globalVar); // 輸出: Hello
console.log(window.globalVar); // 輸出: Hello,因為它是 window 對象的屬性//使用 let 聲明全局變量
let globalLetVar = "Hello";
console.log(globalLetVar); // 輸出: Hello
console.log(window.globalLetVar); // 輸出: undefined(不是 window 的屬性)//使用 const 聲明全局變量
const globalConstVar = "Hello";
console.log(globalConstVar); // 輸出: Hello
console.log(window.globalConstVar); // 輸出: undefined(不是 window 的屬性)

注意,雖然全局變量在某些情況下是必要的,但為了防止命名沖突和提高代碼質量,現代編程實踐中通常不鼓勵過度依賴全局變量。

函數作用域(Function Scope

  • 定義:在函數內部用var聲明的變量和函數參數,作用范圍為整個函數。
  • 特點
    • 在函數內任何位置(包括嵌套代碼塊)可訪問。
  • 示例
function func() {if (true) {var innerVar = '內部變量'; // 屬于函數作用域}console.log(innerVar); // '內部變量'(正常訪問)
}
func();

?此例同時說明,var 聲明的變量沒有塊級作用域,即使在塊(如 if、for、while 等)中聲明,變量仍然屬于包含它的函數或全局作用域。

var 聲明的變量會被提升(hoisting)到當前作用域的頂部,但賦值不會被提升。這意味著變量在聲明之前可以訪問,但值為 undefined。例如:

console.log(hoistedVar); // 輸出: undefined
var hoistedVar = 'I am hoisted';

塊級作用域(ES6+

  • 定義:由?{}?包圍的代碼塊(如?if、for),使用?let?或?const?聲明。
  • 特點
    • 變量僅在塊內有效。
    • 避免循環變量泄露等問題。
  • 示例
if (true) {let blockVar = '塊內變量';const PI = 3.14;
}
console.log(blockVar); // 報錯:blockVar未定義

此例說明,let 和 const 不會被提升,存在“暫時性死區”(Temporal Dead Zone),即聲明前訪問會報錯。

注意

??? ?????? let 和 const 聲明的變量僅在 聲明它們的代碼塊內有效。

??? ?????? 如果在函數體的最外層(不嵌套在任何代碼塊中)聲明,則作用域為 整個函數體(因為函數體本身是一個塊級作用域)。

??? ?????? 如果在函數內的嵌套代碼塊中聲明(如 if 內部),則作用域僅限該代碼塊。

var、let和const的區別

  • var
    • 具有函數作用域(在函數內部聲明的變量只在函數內部有效)。
    • 如果在全局作用域中聲明,則具有全局作用域。
    • 存在變量提升(hoisting),但未初始化的變量會返回undefined。
    • 可以重復聲明同一個變量。
  • let和const
    • 具有塊級作用域(在代碼塊內部聲明的變量只在代碼塊內部有效)。
    • 不會被提升到塊的頂部。
    • 不允許重復聲明同一個變量。
    • let聲明的變量可以重新賦值,而const聲明的變量不能重新賦值(具有只讀性,且必須在聲明時立即賦值,否則報錯))。

2.作用域鏈與閉包

  • 作用域鏈(Scope Chain:函數在定義時確定作用域鏈,逐級向上查找變量。
  • 閉包(Closures:函數保留對外部作用域的引用,即使外部函數已執行完畢。
    • 內部函數可以訪問外部函數的變量。
    • 外部函數執行完畢后,其作用域不會被銷毀,而是被內部函數引用。

作用域鏈示例

let globalVar = "global";function outerFunction() {let outerVar = "outer";function innerFunction() {let innerVar = "inner";console.log(innerVar); // 輸出: innerconsole.log(outerVar); // 輸出: outerconsole.log(globalVar); // 輸出: global}innerFunction();
}outerFunction();

當訪問一個變量時,JavaScript會按照作用域鏈的順序查找變量。作用域鏈是從當前作用域開始,逐級向上查找,直到全局作用域。

閉包示例

function outerFunction() {let outerVar = "I am outer";function innerFunction() {console.log(outerVar); // 訪問外部變量}return innerFunction;
}let myClosure = outerFunction();
myClosure(); // 輸出: I am outer

閉包是指函數可以訪問其外部作用域的變量,即使外部函數已經執行完畢。

附1、嚴格模式(使用'use strict'

  • 在嚴格模式下,未聲明的變量會導致ReferenceError,從而避免全局變量污染。
  • 嚴格模式是ES5引入的一種特殊的運行模式,使代碼在更嚴格的條件下運行。
  • 通過在代碼開頭添加 "use strict" 聲明來啟用。
  • 可以應用于整個腳本或單個函數。

啟用方式

// 整個腳本使用嚴格模式
"use strict";
// 后續代碼...

// 或在函數內使用
function myFunction() {
? ? "use strict";
? ? // 函數代碼...
}
?

示例:非嚴格模式和嚴格模式下未聲明變量直接賦值的行為差異。

假設我們有以下代碼片段:

function myFunction() {x = 10; // 未聲明的變量 xconsole.log(x); // 輸出 x 的值
}myFunction();
console.log(x); // 在全局作用域中訪問 x

1)非嚴格模式下的行為
在非嚴格模式下,如果直接給未聲明的變量賦值,JavaScript 會自動將該變量提升為全局變量。
function myFunction() {
? ? x = 10; // 未聲明的變量 x
? ? console.log(x); // 輸出 10
}

myFunction();
console.log(x); // 輸出 10
解釋:
在myFunction函數中,變量x沒有被聲明(沒有使用var、let或const),但直接賦值為10。
非嚴格模式下,JavaScript 會自動將x提升為全局變量。因此,x在函數內部和全局作用域中都可以被訪問。
這種行為可能導致意外的全局變量污染。


2)嚴格模式下的行為
在嚴格模式下,未聲明的變量直接賦值會拋出ReferenceError。
'use strict'; // 啟用嚴格模式

function myFunction() {
? ? x = 10; // 未聲明的變量 x
? ? console.log(x); // 拋出 ReferenceError : x is not defined
}

myFunction();
console.log(x); // 這行代碼不會被執行
解釋:
在嚴格模式下,JavaScript 不允許直接給未聲明的變量賦值。
如果嘗試給未聲明的變量賦值,JavaScript 會拋出ReferenceError,提示變量未定義。
這種行為可以防止意外創建全局變量,減少潛在的錯誤和命名沖突。
?

關于 JavaScript 嚴格模式的官方文檔可見https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode

附2、可變(Mutable)和不可變(Immutable

“可變”(Mutable)和“不可變”(Immutable)是描述變量或數據是否可以被修改的術語。

1)可變(Mutable

如果一個變量或數據結構的內容可以被修改,那么它就是可變的。這意味著你可以直接改變變量的值或數據結構中的某些部分,而不會創建新的對象。

示例

// 可變的變量

let number = 10;

number = 20; // 修改變量的值,number 現在是 20

// 可變的對象

let obj = { name: "Alice" };

obj.name = "Bob"; // 修改對象的屬性,obj 現在是 { name: "Bob" }

obj.age = 25; // 添加新的屬性,obj 現在是 { name: "Bob", age: 25 }

在上面的例子中:

number 是一個可變的變量,因為它的值可以從 10 改為 20。

obj 是一個可變的對象,因為它的屬性可以被修改或添加。

2)不可變(Immutable

如果一個變量或數據結構的內容不能被修改,那么它就是不可變的。這意味著一旦創建,它的值或內容就無法被改變。如果需要“修改”,通常會創建一個新的對象或變量。

示例

// 不可變的變量(使用 const 聲明)

const PI = 3.14;

PI = 3.14159; // 拋出 TypeError: Assignment to constant variable.

在上面的例子中:

PI 是一個不可變的變量,因為它被 const 聲明,不能被重新賦值。

不可變對象

雖然 JavaScript 中沒有原生的不可變對象,但可以通過一些技術手段(如 Object.freeze())使對象的結構和屬性不可變。

JavaScript復制

const obj = Object.freeze({ name: "Alice" });

obj.name = "Bob"; // 不會報錯,但不會生效,obj 仍然是 { name: "Alice" }

obj.age = 25; // 不會報錯,但不會生效,obj 仍然是 { name: "Alice" }

在上面的例子中:

  • obj 是一個不可變的對象,因為通過 Object.freeze() 方法,它的屬性無法被修改或添加。

3. 可變與不可變的區別

  • 可變數據
    • 可以直接修改。
    • 修改操作通常會影響原始數據。
    • 在某些情況下可能導致意外的副作用(如在函數中修改傳入的對象)。
  • 不可變數據
    • 不能直接修改。
    • 修改操作會創建一個新的對象或數據結構。
    • 更安全,避免了意外修改導致的錯誤。
    • 常用于函數式編程,因為函數式編程強調“無副作用”的函數。

小結

  • 可變(Mutable:可以被修改。
  • 不可變(Immutable:不能被修改。
  • 在 JavaScript 中,let 聲明的變量是可變的,而 const 聲明的變量是不可變的(但對象或數組的內容可以被修改)。
  • 不可變性有助于提高代碼的安全性和可維護性,尤其是在復雜的應用中。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896026.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896026.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896026.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Microsoft 365 Copilot中使用人數最多的是哪些應用

今天在瀏覽Microsoft 365 admin center時發現,copilot會自動整理過去30天內所有用戶使用copilot的概況: 直接把這個圖丟給copilot讓它去分析,結果如下: 總用戶情況 總用戶數在各應用中均為 561 人,說明此次統計的樣本…

ue5.2.1 quixel brideg顯示asset not available in uAsset format

我從未見過如此傻x的bug,在ue5.2.1上通過內置quixel下載資源顯示 asset not available in uAsset format 解決辦法:將ue更新到最新版本,通過fab進入商場選擇資源后add to my library 點擊view in launcher打開epic launcher,就可…

當電腦上有幾個python版本Vscode選擇特定版本python

查看當前vscode用的python版本命令 Import sys print(sys.version) 修改VSCODE解釋器 打開 VSCode。 按下 CtrlShiftP打開命令面板。 輸入 Python: Select Interpreter 并選擇它。 從彈出的列表中選擇你安裝的 Python 解釋器。如果你有多個 Python 版本(例如…

Vue 中 nextTick 的原理詳解

1. 為什么需要 nextTick Vue 采用 異步渲染機制,當響應式數據發生變化時,Vue 并不會立即更新 DOM,而是將這些變化放入一個 隊列 中,并在 同一事件循環(Event Loop)中合并相同的修改,最后執行批…

Spring面試題2

1、compareable和compactor區別 定義與包位置:Comparable是一個接口,位于java.lang包,需要類去實現接口;而Compactor是一個外部比較器,位于java.util包 用法:Comparable只需要實現int compareTo(T o) 方法,比較當前對…

DuodooBMS源碼解讀之 cncw_statement模塊

財務應收應付擴展模組用戶使用手冊 一、模塊概述 財務應收應付擴展模組是一個基于 Odoo18 的擴展模塊,主要對財務應收應付相關功能進行了修改和增強。該模塊增加了多個功能模塊,如預收款單模塊、費用類別設置模塊等,同時對發票、公司、銷售…

JUC并發—9.并發安全集合四

大綱 1.并發安全的數組列表CopyOnWriteArrayList 2.并發安全的鏈表隊列ConcurrentLinkedQueue 3.并發編程中的阻塞隊列概述 4.JUC的各種阻塞隊列介紹 5.LinkedBlockingQueue的具體實現原理 6.基于兩個隊列實現的集群同步機制 4.JUC的各種阻塞隊列介紹 (1)基于數組的阻塞…

vue項目啟動時報錯:error:0308010C:digital envelope routines::unsupported

此錯誤與 Node.js 的加密模塊有關,特別是在使用 OpenSSL 3.0 及以上版本時。Vue 項目在啟動時可能會依賴一些舊的加密算法,而這些算法在 OpenSSL 3.0 中默認被禁用,導致 error:0308010C:digital envelope routines::unsupported 錯誤。 解決…

ncDLRES:一種基于動態LSTM和ResNet的非編碼RNA家族預測新方法

現有的計算方法主要分為兩類:第一類是通過學習序列或二級結構的特征來預測ncRNAs家族,另一類是通過同源序列之間的比對來預測ncRNAs家族。在第一類中,一些方法通過學習預測的二級結構特征來預測ncRNAs家族。二級結構預測的不準確性可能會導致…

愛普生 SG-8101CE 可編程晶振在筆記本電腦的應用

在筆記本電腦的精密架構中,每一個微小的元件都如同精密儀器中的齒輪,雖小卻對整體性能起著關鍵作用。如今的筆記本電腦早已不再局限于簡單的辦公用途,其功能愈發豐富多樣。從日常輕松的文字處理、網頁瀏覽,到專業領域中對圖形處理…

SPRING10_getBean源碼詳細解讀、流程圖

文章目錄 ①. getBean方法的入口-DefaultListableBeanFactory②. DefaultListableBeanFactory調用getBean③. 進入到doGetBean方法④. getSingleton三級緩存方法⑤. getSingleton()方法分析⑥. createBean創建對象方法⑦. 對象創建、屬性賦值、初始化⑧. getBean最詳細流程圖 ①…

IDEA中查詢Maven項目的依賴樹

在Maven項目中,查看項目的依賴樹是一個常見的需求,特別是當你需要了解項目中直接或間接依賴了哪些庫及其版本時。你可以通過命令行使用Maven的dependency:tree插件來做到這一點。這個命令會列出項目中所有依賴的樹狀結構。 打開idea項目的終端&#xff…

深入xtquant:財務數據獲取與應用的實戰指南

深入xtquant:財務數據獲取與應用的實戰指南 在量化交易領域,雖然技術分析和市場情緒分析占據了主導地位,但財務數據作為評估公司基本面的重要依據,同樣不可或缺。xtquant作為一個強大的Python庫,提供了便捷的接口來獲…

windows 安裝 stable diffusion

在windows上安裝 stable diffusion,如果windows沒有nvidia顯卡,想只使用CPU可在webui-user.bat中添加命令 set COMMANDLINE_ARGS--no-half --skip-torch-cuda-test 可正常使用stable diffusion,但速度較慢

Kubernetes控制平面組件:APIServer 基于 引導Token 的認證機制

云原生學習路線導航頁(持續更新中) kubernetes學習系列快捷鏈接 Kubernetes架構原則和對象設計(一)Kubernetes架構原則和對象設計(二)Kubernetes架構原則和對象設計(三)Kubernetes控…

DeepSeek 助力 Vue 開發:打造絲滑的縮略圖列表(Thumbnail List)

前言:哈嘍,大家好,今天給大家分享一篇文章!并提供具體代碼幫助大家深入理解,徹底掌握!創作不易,如果能幫助到大家或者給大家一些靈感和啟發,歡迎收藏關注哦 💕 目錄 Deep…

DeepSeek寫俄羅斯方塊手機小游戲

DeepSeek寫俄羅斯方塊手機小游戲 提問 根據提的要求,讓DeepSeek整理的需求,進行提問,內容如下: 請生成一個包含以下功能的可運行移動端俄羅斯方塊H5文件: 核心功能要求 原生JavaScript實現,適配手機屏幕 …

百問網(100ask)的IMX6ULL開發板的以太網控制器(MAC)與物理層(PHY)芯片(LAN8720A)連接的原理圖分析(包含各引腳說明以及工作原理)

前言 本博文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 。 本博文和博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 的目錄是找出百問網(100ask)的IMX6ULL開發板與NXP官方提供的公板MCIMX6ULL-EVK(imx6ull14x14evk)在以太網硬件…

QT開發技術 【opencv圖片裁剪,平均哈希相似度判斷,以及獲取游戲窗口圖片】

一、圖片裁剪 int CJSAutoWidget::GetHouseNo(cv::Mat matMap) {cv::imwrite(m_strPath "/Data/map.png", matMap);for (int i 0; i < 4; i){for (int j 0; j < 6; j){// 計算當前子區域的矩形cv::Rect roi(j * 20, i * 17, 20, 17);// 提取子區域cv::Mat …

TiDB 是一個分布式 NewSQL 數據庫

TiDB 是一個分布式 NewSQL 數據庫。它支持水平彈性擴展、ACID 事務、標準 SQL、MySQL 語法和 MySQL 協議&#xff0c;具有數據強一致的高可用特性&#xff0c;是一個不僅適合 OLTP 場景還適合 OLAP 場景的混合數據庫。 TiDB是 PingCAP公司自主設計、研發的開源分布式關系型數據…