摘要:所以的作用域是靜態(tài)作用域,也叫詞法作用域。總結(jié)是一門基于詞法作用域靜態(tài)作用域的語言,會沿著作用域鏈像氣泡一樣向外部尋找變量聲明。又是函數(shù)作用域的語言,在中,使用和關(guān)鍵字后,能讓變量處于塊作用域中,而且不存在聲明提升。
本文共 1700 字,讀完只需 7 分鐘概述
變量,編程語言中我們用來模擬現(xiàn)實(shí)概念的工具,比方說,變量可以表示對象,數(shù)組,數(shù)字,字符。既然是工具,那么就用工具的適用范圍,這個工具在這個適用范圍中才有效,在編程語言中,我們稱這個適用范圍叫作用域(scope)。
本文會總結(jié) JS 中作用域的相關(guān)概念。
什么是作用域
全局作用域
函數(shù)作用域
塊級作用域
詞法作用域(靜態(tài)作用域)
作用域鏈
一、什么是作用域?作用域, 英文意思是 scope, 我自己的話來理解就是:
變量訪問規(guī)則的有效范圍
作用域外,無法引用作用域內(nèi)的變量
離開作用域后,作用域的變量的內(nèi)存空間會被清除,比如執(zhí)行完函數(shù)或者關(guān)閉瀏覽器。
二、全局作用域先看一段代碼:
foo = "bar"; console.log(window.foo); // bar
在瀏覽器環(huán)境中聲明變量,該變量會默認(rèn)成為全局 windows 對象的屬性。
再看下面這段代碼:
function foo() { name = "bar" } foo(); console.log(window.name) // bar
在函數(shù)中,如果不加 bar聲明一個變量,那么這個變量會默認(rèn)被聲明為全局變量,如果是嚴(yán)格模式則會報錯。
全局變量可以在任何地方訪問到,但是有很大的問題存在。
全局變量會造成命名污染,如果在多處對同一個全局變量進(jìn)行操作,那么就會覆蓋全局變量的定義。同時全局變量數(shù)量過多,非常不方便管理。
這也是為什么像jQuery 和 underscore 這樣的類庫,要在全局建立 $ 和 _ 變量,其余私有方法屬性掛載到該全局變量下。
三、函數(shù)作用域JS 是函數(shù)作用域,在函數(shù)中定義一個局部變量,那么該變量只可以在該函數(shù)作用域中被訪問。
function doSomething() { var thing = "吃早餐"; } console.log(thing); // Uncaught ReferenceError: thing is not defined
嵌套函數(shù)作用域:
function outter() { var thing = "吃早餐"; function inner() { console.log(thing); } inner(); } outter(); // 吃早餐
在外層函數(shù)中,嵌套一個內(nèi)層函數(shù),那么這個內(nèi)層函數(shù)可以向上訪問到外部作用域的變量。
那么,既然內(nèi)層函數(shù)可以訪問到外層函數(shù)的變量,那么把內(nèi)層函數(shù)返回后呢?
function outter() { var thing = "吃晚餐"; function inner() { console.log(thing); } return inner; } var foo = outter(); foo(); // 吃晚餐 前面我們提到了,函數(shù)執(zhí)行完后,函數(shù)作用域的變量會被垃圾回收,以上代碼可以看出當(dāng)我們返回了一個訪問了外部函數(shù)變量的內(nèi)部函數(shù),最后外部函數(shù)的變量得以保存。 這種當(dāng)變量存在的函數(shù)已經(jīng)執(zhí)行結(jié)束,但仍在可以訪問的方式就是`閉包`。 閉包的具體實(shí)踐,后續(xù)文章會詳細(xì)說明。四、塊級作用域
JS 在 ES6 之前只有函數(shù)作用域,沒有塊級作用域的概念。
看一下代碼:
function doSomething() { for (var i = 0; i < 10; i++) { ... } console.log(i) } doSomething(); // 10
由于 JS 沒有塊級作用域,變量 i 在函數(shù)作用域中只有一個,每次 for 循壞都在改變這一個變量。
再看阮一峰老師 ES6 教程里的一段代碼:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10;
以上代碼中,由于沒有塊級作用域,i 變量全局只有一個,當(dāng) for 循壞結(jié)束,變量 i 的值等于 10, 所以 a[6]() 對應(yīng)函數(shù)內(nèi)的變量 i 的打印值就是 10。
ES 6 中通過 let 和 const關(guān)鍵字 引用了塊級作用域的概念,所謂塊級作用域,就是以 {}包裹的區(qū)域。
我們將阮一峰老師 ES6 教程里的一段代碼改成 let 的形式:
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6;
這時,數(shù)組內(nèi)的索引為6函數(shù)內(nèi)的變量打印值為6,每次循環(huán),會創(chuàng)建新的塊級作用域,然后重新聲明一個新的變量 i;JS 的解釋引擎會記住上次循環(huán)的變量值,所以能夠返回正確的結(jié)果。
let 和 const 會聲明一個塊級作用域的變量及常量,不易發(fā)生變量命名污染的問題,能規(guī)避沖突,幫助你寫出簡潔優(yōu)雅的代碼,建議一直使用。
五、詞法作用域(靜態(tài)作用域)詞法作用域,也可以叫做靜態(tài)作用域,是什么意思呢?
無論函數(shù)在哪里調(diào)用,詞法作用域都只由函數(shù)被聲明時所處的位置決定。
既然有靜態(tài)作用域,那么也有動態(tài)作用域。
而動態(tài)作用域的作用域則是由函數(shù)被調(diào)用執(zhí)行的位置所決定。
var a = 123; function func1() { console.log(a); } function func2() { var a = 456; func1(); } func2(); // 123
以上代碼,最后輸出結(jié)果 a 的值,來自于 func1 聲明時所在位置訪問到的 a 值 123。
所以 JS 的作用域是靜態(tài)作用域,也叫詞法作用域。
六、作用域鏈在 JS 引擎中,通過標(biāo)識符查找標(biāo)識符的值,會從當(dāng)前作用域向上尋找,直到作用域找到第一個匹配的標(biāo)識符為止。就是 JS 的作用域鏈
如果嵌套作用域有多個相同標(biāo)識符,那么,最內(nèi)部的標(biāo)識符會覆蓋外層標(biāo)識符,這叫做“遮蔽效應(yīng)”
var a = 1; function func1() { var a = 2; function func2() { var a = 3; console.log(a); // 3 } func2(); } func1(); // 3
func2 中變量 a,會從內(nèi)部開始向外部上層尋找,找到最近的 a 標(biāo)識符的聲明為止。
JS 是一門基于詞法作用域(靜態(tài)作用域)的語言,JS 會沿著作用域鏈像氣泡一樣向外部尋找變量聲明。
JS 又是函數(shù)作用域的語言,在 ES6 中,使用 let 和 const 關(guān)鍵字后,能讓變量處于塊作用域中,而且不存在聲明提升。
后面的文章會介紹 JS 中的聲明提升和閉包,敬請期待。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/98330.html
摘要:查詢是在作用域鏈中,一級級的往上查找該變量的引用。作用域和作用域鏈作用域的概念,應(yīng)該兩張圖幾句話就能解釋吧。這個建筑代表程序中的嵌套作用域鏈。一層嵌一層的作用域形成了作用域鏈,變量在作用域鏈中的函數(shù)內(nèi)得到了自己的定義。 javascript作用域和閉包之我見 看了《你不知道的JavaScript(上卷)》的第一部分——作用域和閉包,感受頗深,遂寫一篇讀書筆記加深印象。路過的大牛歡迎指點(diǎn)...
摘要:關(guān)于兩個專業(yè)術(shù)語的討論起自對你不知道的一書的閱讀學(xué)習(xí)。遇到,編譯器會詢問作用域是否已經(jīng)有一個該名稱的變量存在于同一個作用域的集合中。摘錄來自你不知道的。 JS 編譯之 LHS RHS 一、前言 最近和朋友聊技術(shù)的時候,聊到 LHS RHS,我竟然沒聽說過 沒聽說過。。。 于是成功引起了我的好奇心。 關(guān)于兩個專業(yè)術(shù)語的討論起自對《你不知道的JavaScript》一書的閱讀學(xué)習(xí)。 二、編譯...
摘要:對象數(shù)組初始化表達(dá)式,闖關(guān)記之上文檔對象模型是針對和文檔的一個。闖關(guān)記之?dāng)?shù)組數(shù)組是值的有序集合。數(shù)組是動態(tài)的,根闖關(guān)記之語法的語法大量借鑒了及其他類語言如和的語法。 《JavaScript 闖關(guān)記》之 DOM(下) Element 類型 除了 Document 類型之外,Element 類型就要算是 Web 編程中最常用的類型了。Element 類型用于表現(xiàn) XML 或 HTML 元素...
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創(chuàng)建的函數(shù),其作用域指向全局作用域。所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。 作用域 定義 在編程語言中,作用域控制著變量與參數(shù)的可見性及生命周期,它能減少名稱沖突,而且提供了自動內(nèi)存管理 --javascript 語言精粹 我理解的是,一個變量、函數(shù)或者成員可以在代碼中訪問到的范圍。 js的變量作...
閱讀 2883·2021-11-24 09:39
閱讀 2455·2019-08-30 15:53
閱讀 3025·2019-08-30 13:47
閱讀 1296·2019-08-30 12:50
閱讀 1481·2019-08-29 16:31
閱讀 2642·2019-08-29 13:14
閱讀 1559·2019-08-29 10:55
閱讀 790·2019-08-26 13:32