這篇文章給大家分享的是有關(guān)JS作用域的陷阱有哪些的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
創(chuàng)新互聯(lián)公司是一家網(wǎng)站設(shè)計公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營產(chǎn)品:響應(yīng)式網(wǎng)站設(shè)計、高端網(wǎng)站設(shè)計、營銷型網(wǎng)站。我們專注企業(yè)品牌在網(wǎng)站中的整體樹立,網(wǎng)絡(luò)互動的體驗,以及在手機等移動端的優(yōu)質(zhì)呈現(xiàn)。成都網(wǎng)站制作、做網(wǎng)站、移動互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運營、VI設(shè)計、云產(chǎn)品.運維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場的競爭激烈,認真對待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價值服務(wù)。
在 JavaScript 中,代碼塊、函數(shù)或模塊為變量創(chuàng)建作用域。例如 if
代碼塊為變量 message
創(chuàng)建作用域:
if (true) { const message = 'Hello'; console.log(message); // 'Hello' } console.log(message); // throws ReferenceError
在 if
代碼塊作用域內(nèi)可以訪問 message
。但是在作用域之外,該變量不可訪問。
好的,這是作用域的簡短介紹。如果你想了解更多信息,建議閱讀我的文章用簡單的詞解釋 JavaScript 作用域。
以下是 5 種有趣的情況,其中 JavaScript 作用域的行為與你預(yù)期的不同。你可能會研究這些案例以提高對作用域的了解,或者只是為面試做準(zhǔn)備。
思考以下代碼片段:
const colors = ['red', 'blue', 'white']; for (let i = 0, var l = colors.length; i < l; i++) { console.log(colors[i]); // 'red', 'blue', 'white' } console.log(l); // ??? console.log(i); // ???
當(dāng)你打印 l
和 i
變量時會發(fā)生什么?
console.log(l)
輸出數(shù)字 3
,而 console.log(i)
則拋出 ReferenceError
。
l
變量是使用 var
語句聲明的。你可能已經(jīng)知道,var
變量僅受函數(shù)體作用域限制而并非代碼塊。
相反,變量 i
使用 let
語句聲明。因為 let
變量是塊作用域的,所以 i
僅在 for
循環(huán)作用域內(nèi)才可訪問。
把 l
聲明從 var l = colors.length
改為 const l = colors.length
?,F(xiàn)在變量 l
被封裝在 for
循環(huán)體內(nèi)。
在以下代碼段中:
// ES2015 env { function hello() { return 'Hello!'; } } hello(); // ???
調(diào)用 hello()
會怎樣? (代碼段在 ES2015 環(huán)境中執(zhí)行)
因為代碼塊為函數(shù)聲明創(chuàng)建了作用域,所以在 ES2015 環(huán)境中調(diào)用 hello()
會引發(fā) ReferenceError: hello is not defined
。
有趣的是,在 ES2015 之前的環(huán)境中,在執(zhí)行上述代碼段時不會拋出錯誤。 你知道為什么嗎?請在下面的評論中寫下你的答案!
你可以在代碼塊中導(dǎo)入模塊嗎?
if (true) { import { myFunc } from 'myModule'; // ??? myFunc(); }
上面的腳本將觸發(fā)錯誤: 'import' and 'export' may only appear at the top-level
。
你只能在模塊文件的最頂級作用域(也稱為模塊作用域)中導(dǎo)入模塊。
始終從模塊作用域?qū)肽K。另外一個好的做法是將 import
語句放在源文件的開頭:
import { myFunc } from 'myModule'; if (true) { myFunc(); }
ES2015 的模塊系統(tǒng)是靜態(tài)的。通過分析 JavaScript 源代碼而不是執(zhí)行代碼來確定模塊的依賴關(guān)系。所以在代碼塊或函數(shù)中不能包含 import
語句,因為它們是在運行時執(zhí)行的。
思考以下函數(shù):
let p = 1; function myFunc(p = p + 1) { return p; } myFunc(); // ???
調(diào)用 myFunc()
會發(fā)生什么?
當(dāng)調(diào)用函數(shù) myFunc()
時,將會引發(fā)錯誤: ReferenceError: Cannot access 'p' before initialization
。
發(fā)生這種情況是因為函數(shù)的參數(shù)具有自己的作用域(與函數(shù)作用域分開)。參數(shù) p = p + 1
等效于 let p = p + 1
。
讓我們仔細看看 p = p + 1
。
首先,定義變量 p
。然后 JavaScript 嘗試評估默認值表達式 p + 1
,但此時綁定 p
已經(jīng)創(chuàng)建但尚未初始化(不能訪問外部作用域的變量 let p = 1
)。因此拋出一個錯誤,即在初始化之前訪問了 p
。
為了解決這個問題,你可以重命名變量 let p = 1
,也可以重命名功能參數(shù) p = p + 1
。
讓我們選擇重命名函數(shù)參數(shù):
let p = 1; function myFunc(q = p + 1) { return q; } myFunc(); // => 2
函數(shù)參數(shù)從 p
重命名為 q
。當(dāng)調(diào)用 myFunc()
時,未指定參數(shù),因此將參數(shù) q
初始化為默認值 p + 1
。為了評估 p +1
,訪問外部作用域的變量 p
:p +1 = 1 + 1 = 2
。
以下代碼在代碼塊內(nèi)定義了一個函數(shù)和一個類:
if (true) { function greet() { // function body } class Greeter { // class body } } greet(); // ??? new Greeter(); // ???
是否可以在塊作用域之外訪問 greet
和 Greeter
? (考慮 ES2015 環(huán)境)
function
和 class
聲明都是塊作用域的。所以在代碼塊作用域外調(diào)用函數(shù) greet()
和構(gòu)造函數(shù) new Greeter()
就會拋出 ReferenceError
。
必須注意 var
變量,因為它們是函數(shù)作用域的,即使是在代碼塊中定義的。
由于 ES2015 模塊系統(tǒng)是靜態(tài)的,因此你必須在模塊作用域內(nèi)使用 import
語法(以及 export
)。
函數(shù)參數(shù)具有其作用域。設(shè)置默認參數(shù)值時,請確保默認表達式內(nèi)的變量已經(jīng)用值初始化。
在 ES2015 運行時環(huán)境中,函數(shù)和類聲明是塊作用域的。但是在 ES2015 之前的環(huán)境中,函數(shù)聲明僅在函數(shù)作用域內(nèi)。
感謝各位的閱讀!關(guān)于“JS作用域的陷阱有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!