摘要:作用域鏈前面說,作用域是根據(jù)名稱查找變量的一套規(guī)則。把這樣一層一層嵌套的作用域,叫做作用域鏈。因為這個函數(shù)名無法被外部作用域所訪問。的進(jìn)階用法是給其傳入?yún)?shù)這樣的好處是可以縮短查詢時的作用域鏈。
上一篇文章中分析了 JS 中的數(shù)據(jù)類型和變量。這一篇文章將分析作用域,以及回答上一篇文章中變量提升的原因。
什么是作用域作用域是一套規(guī)則,保存著變量,等待被引擎所查找。
var a = 1; console.log(a); // => 1 console.log(b); // => ReferenceError
當(dāng)打印 a 時,引擎就去作用域中查找 a,找到把結(jié)果返回。如果查找失敗,那么就會報錯。
詞法作用域JS 采用的詞法作用域,也可以說是靜態(tài)作用域。簡單來說,詞法作用域是由寫代碼時將變量寫在哪里決定的。
先看一段代碼:
var a = 1; function fn() { var a = 2; return a; } fn(); // => 2
當(dāng)執(zhí)行函數(shù) fn 時,會返回 2,而不是 1。
作用域查找JS 引擎會進(jìn)行兩種查找,LHS 和 RHS。怎么理解?L 和 R 可以說代表左和右。什么的左和右?賦值操作的。
這里的賦值操作不一定出現(xiàn) =,比如參數(shù)傳遞也是一個賦值操作。
當(dāng)變量出現(xiàn)在賦值操作的左邊時,引擎就會對這個變量進(jìn)行 LHS 查找;當(dāng)出現(xiàn)在右邊時(這個還可以理解為取得變量的源值),就會進(jìn)行 RHS 查找。
function foo(a) { console.log(a); } foo(2);
對于變量 a 來說,引擎會進(jìn)行兩次查找,1 次 LHS,1 次 RHS。
調(diào)用 foo(),并傳入?yún)?shù) 2,這時存在著一個賦值操作即 a = 2,進(jìn)行一次 LHS 查找。打印 a 時,需要獲取 a 的源值,所以進(jìn)行一次 RHS 查找。
如果查詢失敗呢?
對于 LHS 來說,給未聲明的賦值就會查詢失敗。
a = 2;
但是我們知道,上面的代碼在非嚴(yán)格模式下并不會報錯,而變量 a 會被自動創(chuàng)建。
而對于 RHS 來說,直接使用未聲明的變量就會報 ReferenceError。
console.log(a); // => ReferenceError
另外,RHS 雖然查詢成功,但是卻對查詢結(jié)果進(jìn)行非法操作,就會報 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
當(dāng)引擎對 b 進(jìn)行 RHS 查找時,在當(dāng)前作用域無法找到,引擎就會在外層作用域中查找,直到找到這個變量,或者直到抵達(dá)最外層作用域(全局作用域)為止。
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ù)表達(dá)式利用函數(shù)作用域,可以將外部作用域無法訪問的內(nèi)容包裝起來。但是,帶來了額外的一個問題,函數(shù)名本身“污染”了所在的作用域。
這時,就提出了 IIFE(立即執(zhí)行函數(shù)表達(dá)式)。
(function foo() { // ... }());
即包裝了內(nèi)部函數(shù),又避免了引入函數(shù)名。因為這個函數(shù)名無法被外部作用域所訪問。
IIFE 的進(jìn)階用法是給其傳入?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ù)表達(dá)式不會被提升。
var foo = 1; var foo = function () {} typeof foo; // => "function"小結(jié)
這篇文章梳理了 JavaScript 中作用域的基本知識。
接下來會介紹執(zhí)行上下文和閉包這兩個概念,它們與作用域息息相關(guān)。
關(guān)于這是我的公眾號,記錄著我的前端博客,沒事兒也分享一些電影、書籍。
歡迎一起交流學(xué)習(xí)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/99470.html
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...
摘要:講作用域鏈?zhǔn)紫纫獜淖饔糜蛑v起,下面是百度百科里對作用域的定義作用域在許多程序設(shè)計語言中非常重要。原文出處談?wù)務(wù)Z法里一些難點問題二 3) 作用域鏈相關(guān)的問題 作用域鏈?zhǔn)莏avascript語言里非常紅的概念,很多學(xué)習(xí)和使用javascript語言的程序員都知道作用域鏈?zhǔn)抢斫鈐avascript里很重要的一些概念的關(guān)鍵,這些概念包括this指針,閉包等等,它非常紅的另一個重要原因就...
摘要:作用域是代碼的不同部分在運(yùn)行期間的可見性。大多數(shù)開發(fā)者想當(dāng)然地理解作用域,但毫無疑問,有它自己的說明。變量可能是全局作用域的,或者是方法作用域的。總而言之,不要重復(fù)聲明變量,使用良好命名,盡力避免在聲明前調(diào)用和執(zhí)行任何東西。 原文鏈接:https://hackernoon.com/unders... 什么是作用域? 就像JavaScript中的其他東西一樣,作用域并無特別之處。盡管大多...
摘要:理解作用域高級程序設(shè)計中有說到對象是在運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的在全局函數(shù)中,等于,而當(dāng)函數(shù)被作為某個對象調(diào)用時,等于那個對象。指向與匿名函數(shù)沒有關(guān)系如果函數(shù)獨立調(diào)用,那么該函數(shù)內(nèi)部的,則指向。 理解this作用域 《javascript高級程序設(shè)計》中有說到: this對象是在運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局函數(shù)中,this等于window,而當(dāng)函數(shù)被作為某個對象調(diào)用時,t...
摘要:針對有經(jīng)驗的開發(fā)者,糾正一個過時的理解你可能聽過這句話沒有塊級作用域。詳見而且,在不使用新語法的前提下,沒有塊級作用域的正確理解應(yīng)該是只有全局作用域和函數(shù)作用域。各自的作用域下,用各自的。 針對有經(jīng)驗的開發(fā)者,糾正一個過時的理解:你可能聽過這句話javascript沒有塊級作用域。所謂塊,就是大括號{}中間的語句。誠然,在ES6之前,這句話是完全正確的,但ES中新增的兩個命令let和c...
閱讀 1655·2021-09-26 09:55
閱讀 5248·2021-09-22 15:40
閱讀 2013·2019-08-30 15:53
閱讀 1497·2019-08-30 11:15
閱讀 1714·2019-08-29 15:41
閱讀 1869·2019-08-28 18:13
閱讀 3146·2019-08-26 12:00
閱讀 1668·2019-08-26 10:30