日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

理解 JavaScript 作用域

發(fā)布時間:2025/3/8 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解 JavaScript 作用域 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上一篇文章中分析了 JS 中的數(shù)據(jù)類型和變量。這一篇文章將分析作用域,以及回答上一篇文章中變量提升的原因。

什么是作用域

作用域是一套規(guī)則,保存著變量,等待被引擎所查找。

var a = 1; console.log(a); // => 1 console.log(b); // => ReferenceError

當打印 a 時,引擎就去作用域中查找 a,找到把結(jié)果返回。如果查找失敗,那么就會報錯。

詞法作用域

JS 采用的詞法作用域,也可以說是靜態(tài)作用域。簡單來說,詞法作用域是由寫代碼時將變量寫在哪里決定的。

先看一段代碼:

var a = 1;function fn() {var a = 2;return a; }fn(); // => 2

當執(zhí)行函數(shù) fn 時,會返回 2,而不是 1。

作用域查找

JS 引擎會進行兩種查找,LHS 和 RHS。怎么理解?L 和 R 可以說代表左和右。什么的左和右?賦值操作的。

這里的賦值操作不一定出現(xiàn) =,比如參數(shù)傳遞也是一個賦值操作。

當變量出現(xiàn)在賦值操作的左邊時,引擎就會對這個變量進行 LHS 查找;當出現(xiàn)在右邊時(這個還可以理解為取得變量的源值),就會進行 RHS 查找。

function foo(a) {console.log(a); }foo(2);

對于變量 a 來說,引擎會進行兩次查找,1 次 LHS,1 次 RHS。

調(diào)用 foo(),并傳入?yún)?shù) 2,這時存在著一個賦值操作即 a = 2,進行一次 LHS 查找。打印 a 時,需要獲取 a 的源值,所以進行一次 RHS 查找。

如果查詢失敗呢?

對于 LHS 來說,給未聲明的賦值就會查詢失敗。

a = 2;

但是我們知道,上面的代碼在非嚴格模式下并不會報錯,而變量 a 會被自動創(chuàng)建。

而對于 RHS 來說,直接使用未聲明的變量就會報 ReferenceError。

console.log(a); // => ReferenceError

另外,RHS 雖然查詢成功,但是卻對查詢結(jié)果進行非法操作,就會報 TypeError。

var foo = 1; foo(); // => TypeError

作用域鏈

前面說,作用域是根據(jù)名稱查找變量的一套規(guī)則。而在實際情況中,經(jīng)常出現(xiàn)多個作用域嵌套的情況。

function foo(a) {console.log(a + b); } var b = 2; foo(2); // => 4

當引擎對 b 進行 RHS 查找時,在當前作用域無法找到,引擎就會在外層作用域中查找,直到找到這個變量,或者直到抵達最外層作用域(全局作用域)為止。

LHS 查找也是如此。

把這樣一層一層嵌套的作用域,叫做作用域鏈。

函數(shù)作用域

函數(shù)作用域是指,屬于這個函數(shù)的全部變量都可以在這個函數(shù)的范圍內(nèi)使用及復(fù)用。

function foo() {var a = 1; }console.log(a); // => ReferenceError

也就是說,函數(shù)外部將無法訪問函數(shù)內(nèi)部的變量。

但是這卻是非常有用的。我們可以利用函數(shù)隱藏內(nèi)部實現(xiàn),使其外部無法訪問、修改等。

立即執(zhí)行函數(shù)表達式

利用函數(shù)作用域,可以將外部作用域無法訪問的內(nèi)容包裝起來。但是,帶來了額外的一個問題,函數(shù)名本身“污染”了所在的作用域。

這時,就提出了 IIFE(立即執(zhí)行函數(shù)表達式)。

(function foo() {// ... }());

即包裝了內(nèi)部函數(shù),又避免了引入函數(shù)名。因為這個函數(shù)名無法被外部作用域所訪問。

IIFE 的進階用法是給其傳入?yún)?shù):

(function fn(global) {// ... })(window);

這樣的好處是可以縮短查詢時的作用域鏈。

塊作用域

ES6,通過 let 和 const 引入了塊作用域。

if (true) {let a = 1; } console.log(a); // => ReferenceError

變量提升

上一篇文章中中提到了變量提升。

在 JS 中,var a = 1; 這行代碼其實會被看成 var a 和 a = 2,并在兩個階段去執(zhí)行。

在編譯階段,執(zhí)行聲明操作;在執(zhí)行階段,執(zhí)行賦值操作。

所有的變量聲明都會被提升到作用域的頂部,這個過程叫做“提升”。

函數(shù)聲明也會發(fā)生提升,并且函數(shù)聲明會先于變量提升:

var foo = 1; function foo () {}typeof foo; // => 'number'

注意,只有函數(shù)聲明會被提升,而函數(shù)表達式不會被提升。

var foo = 1; var foo = function () {}typeof foo; // => 'function'

小結(jié)

這篇文章梳理了 JavaScript 中作用域的基本知識。

接下來會介紹執(zhí)行上下文和閉包這兩個概念,它們與作用域息息相關(guān)。

關(guān)于

這是我的公眾號,記錄著我的前端博客,沒事兒也分享一些電影、書籍。

歡迎一起交流學(xué)習(xí)。

總結(jié)

以上是生活随笔為你收集整理的理解 JavaScript 作用域的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。