目錄
全域作用域
模組作用域
函數作用域
區塊作用域
詞法作用域
作用域鏈
總結
首頁 web前端 js教程 JavaScript作用域的全面解析(附程式碼)

JavaScript作用域的全面解析(附程式碼)

Apr 03, 2019 am 10:27 AM
javascript 作用域 前端

這篇文章帶給大家的內容是關於JavaScript作用域的全面解析(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

作用域決定了變數的生命週期和可見性,變數在作用域範圍之外是不可見的。

JavaScript 的作用域包括:模組作用域,函數作用域,區塊作用域,詞法作用域和全域作用域。

全域作用域

在任何函數、區塊或模組範圍之外定義的變數具有全域作用域。可以在程式的任意位置存取全域變數。

當啟用模組系統時,建立全域變數會變得困難,但仍然可以做到這一點。可以在 HTML 中定義一個變量,這個變數需要在函數之外聲明,這樣就可以建立一個全域變數:

<script>
  let GLOBAL_DATA = { value : 1};
</script>
console.log(GLOBAL_DATA);
登入後複製

當沒有模組系統時,建立全域變數會容易很多。在任何文件中的函數外聲明的變數都是全域變數。

全域變數貫穿程式的整個生命週期。

另一種建立全域變數的方法是在程式的任意位置使用window 全域物件:

window.GLOBAL_DATA = { value: 1 };
登入後複製

這樣GLOBAL_DATA 變數會隨處可見。

console.log(GLOBAL_DATA)
登入後複製

不過你也知道這種做法是不好的。

模組作用域

如果不啟用模組,在所有函數之外宣告的變數是全域變數。在模組中,在函數外部宣告的變數都是隱藏的,除非明確導出,否則不可用於其他模組。

匯出使函數或物件可用於其他模組。在這個範例中,我從模組檔案 sequence.js 中導出了一個函數:

// in sequence.js
export { sequence, toList, take };
登入後複製

目前模組可以透過匯入來使用其他模組的函數或物件成。

import { sequence, toList, toList } from "./sequence";
登入後複製

在某種程度上,我們可以認為模組是一個自動執行的函數,它將 import 的資料作為輸入,然後傳回 export 的資料。

函數作用域

函數作用域意味著在函數中定義的參數和變數在函數內的任何位置都可見,但是在函數外部不可見。

下面是一個自動執行的函數,稱為IIFE。

(function autoexecute() {
    let x = 1;
})();
console.log(x);
//Uncaught ReferenceError: x is not defined
登入後複製

IIFE 的意思是立即呼叫函數表達式,是一個在定義後立即運行的函數。

var 宣告的變數只有函數作用域。更重要的是,用 var 宣告的變數被提升到其作用域的頂端。透過這種方式,可以在聲明之前存取它們。看看下面的程式碼:

function doSomething(){
  console.log(x);
  var x = 1;
}
doSomething(); //undefined
登入後複製

這種事不會發生在 let 中。用 let 宣告的變數只能在定義後存取。

function doSomething(){
  console.log(x);
  let x = 1;
}
doSomething();
//Uncaught ReferenceError: x is not defined
登入後複製

var 宣告的變數可以在同一作用域下多次重新宣告:

function doSomething(){
  var x = 1
  var x = 2;
  console.log(x);
}
doSomething();
登入後複製

letconst 宣告的變數不能在同一作用域內重新宣告:

function doSomething(){
  let x = 1
  let x = 2;
}
//Uncaught SyntaxError: Identifier 'x' has already been declared
登入後複製

也許我們可以不必關心這一點,因為var 已經開始變得過時了。

區塊作用域

區塊作用域用花括號定義。它由 {} 分隔。

letconst 宣告的變數可以受到區塊作用域的約束,只能在定義它們的區塊中存取。

思考下面這段關於let 區塊範圍的程式碼:

let x = 1;
{ 
  let x = 2;
}
console.log(x); //1
登入後複製

#相反,var 宣告不受區塊作用域的約束:

var x = 1;
{ 
  var x = 2;
}
console.log(x); //2
登入後複製

另一個常見問題是在循環中使用類似setTimeout() 的非同步操作。下面的循環程式碼將顯示五次數字 5。

(function run(){
    for(var i=0; i<5; i++){
        setTimeout(function logValue(){
            console.log(i);         //5
        }, 100);
    }
})();
登入後複製

帶有 let 宣告的 for 迴圈語句在每次迴圈都會建立一個新的變數並設定到區塊作用域。下一段循環程式碼將會顯示 0 1 2 3 4 5

(function run(){
  for(let i=0; i<5; i++){
    setTimeout(function log(){
      console.log(i); //0 1 2 3 4
    }, 100);
  }
})();
登入後複製

詞法作用域

詞法作用域是內部函數存取定義它的外部作用域的能力。

看這段程式碼:

(function autorun(){
    let x = 1;
    function log(){
      console.log(x);
    };
    
    function run(fn){
      let x = 100;
      fn();
    }
    
    run(log);//1
})();
登入後複製

log 函數是一個閉包。它從父函數 autorun() 引用 x 變量,而不是 run() 函數中的 x 變數。

閉包函數可以存取建立它的作用域,而不是它自己的作用域。

autorun() 的局部函數作用域是 log() 函數的詞法作用域。

作用域鏈

每個作用域都有一個指向父作用域的連結。當使用變數時,JavaScript 會向下查看作用域鏈,直到它找到所要求的變數或到達全域作用域(即作用域鏈的末端)。
看下面這個範例:

let x0 = 0;
(function autorun1(){
 let x1 = 1;
  
 (function autorun2(){
   let x2 = 2;
  
   (function autorun3(){
     let x3 = 3;
      
     console.log(x0 + " " + x1 + " " + x2 + " " + x3);//0 1 2 3
    })();
  })();
})();
登入後複製

內部函數 autorun3()  可以存取本地 x3 變數。也可以從外部函數存取變數 x1x2 和全域變數 x0

如果找不到變量,它將在嚴格模式下傳回錯誤。

"use strict";
x = 1;
console.log(x)
//Uncaught ReferenceError: x is not defined
登入後複製

非嚴格模式也被稱為“草率模式”,它會草率的創建一個全域變數。

x = 1;
console.log(x); //1
登入後複製

總結

在全域作用域中定義的變數可在程式的任何位置使用。

在模組中,在函數外部宣告的變數都是隱藏的,除非被明確導出,否則不可用於其他模組。

函數作用域表示函數中定義的參數和變數在函數的任意位置都可見

letconst 宣告的變數具有塊作用域。 var 沒有區塊作用域。

【相關推薦: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)

c語言中typedef struct的用法 c語言中typedef struct的用法 May 09, 2024 am 10:15 AM

typedef struct 在 C 語言中用於建立結構體類型別名,簡化結構體使用。它透過指定結構體別名將一個新的資料類型作為現有結構體的別名。優點包括增強可讀性、程式碼重複使用和類型檢查。注意:在使用別名前必須定義結構體,別名在程式中必須唯一且僅在其宣告的作用域內有效。

java中的variable expected怎麼解決 java中的variable expected怎麼解決 May 07, 2024 am 02:48 AM

Java 中的變數期望值異常可以透過以下方法解決:初始化變數;使用預設值;使用 null 值;使用檢查和賦值;了解局部變數的作用域。

js中閉包的優缺點 js中閉包的優缺點 May 10, 2024 am 04:39 AM

JavaScript 閉包的優點包括維持變數作用域、實作模組化程式碼、延遲執行和事件處理;缺點包括記憶體洩漏、增加了複雜性、效能開銷和作用域鏈影響。

c++中的include什麼意思 c++中的include什麼意思 May 09, 2024 am 01:45 AM

C++ 中的 #include 預處理器指令將外部來源檔案的內容插入到目前原始檔案中,以複製其內容到目前原始檔案的相應位置。主要用於包含頭文件,這些頭文件包含程式碼中所需的聲明,例如 #include <iostream> 是包含標準輸入/輸出函數。

C++ 智慧指標:全面剖析其生命週期 C++ 智慧指標:全面剖析其生命週期 May 09, 2024 am 11:06 AM

C++智慧指標的生命週期:建立:分配記憶體時建立智慧指標。所有權轉移:透過移動操作轉移所有權。釋放:智慧指標離開作用域或被明確釋放時釋放記憶體。物件銷毀:所指向物件被銷毀時,智慧型指標成為無效指標。

c++中函數的定義和呼叫可以巢狀嗎 c++中函數的定義和呼叫可以巢狀嗎 May 06, 2024 pm 06:36 PM

可以。 C++ 允許函數巢狀定義和呼叫。外部函數可定義內建函數,內部函數可在作用域內直接呼叫。巢狀函數增強了封裝性、可重複用性和作用域控制。但內部函數無法直接存取外部函數的局部變量,且傳回值類型需與外部函數宣告一致,內部函數不能自遞歸。

vue中let和var的區別 vue中let和var的區別 May 08, 2024 pm 04:21 PM

在 Vue 中,let 和 var 宣告變數時在作用域上存在差異:作用域:var 具有全域作用域,let 具有區塊級作用域。區塊級作用域:var 不會建立區塊級作用域,let 建立區塊級作用域。重新宣告:var 允許在同一作用域內重新宣告變數,let 不允許。

C++ 智慧指標:從基礎到高級 C++ 智慧指標:從基礎到高級 May 09, 2024 pm 09:27 PM

智慧指針是C++專用指針,能夠自動釋放堆記憶體對象,避免記憶體錯誤。類型包括:unique_ptr:獨佔所有權,指向單一物件。 shared_ptr:共享所有權,允許多個指標同時管理物件。 weak_ptr:弱引用,不增加引用計數,避免循環引用。使用方法:使用std命名空間的make_unique、make_shared和make_weak建立智慧指標。智慧型指標在作用域結束時自動釋放物件記憶體。進階用法:可以使用自訂刪除器控制物件釋放方式。智慧型指標可有效管理動態數組,防止記憶體洩漏。

See all articles