十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
這篇文章將為大家詳細(xì)講解有關(guān)JavaScript中關(guān)于作用域的詳細(xì)介紹,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
新鄉(xiāng)網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,新鄉(xiāng)網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為新鄉(xiāng)上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的新鄉(xiāng)做網(wǎng)站的公司定做!
幾乎所有的編程語(yǔ)言都有作用域的概念,那作用域到底指的是什么呢?作用域就是編程語(yǔ)言在定義變量時(shí),變量如何存儲(chǔ)、變量如何訪問(wèn)的一套規(guī)則,不同的編程語(yǔ)言的規(guī)則大同小異,接下來(lái)就來(lái)看看這套規(guī)則是怎么設(shè)定的
編譯原理
在傳統(tǒng)編譯語(yǔ)言中,在代碼執(zhí)行之前都會(huì)有一個(gè)編譯過(guò)程:
和傳統(tǒng)編譯語(yǔ)言不太一樣,js的編譯和執(zhí)行并不是分開(kāi)執(zhí)行,大多數(shù)情況都是編譯過(guò)程結(jié)束就會(huì)立刻執(zhí)行,為了在短時(shí)間的編譯過(guò)程內(nèi)達(dá)到較優(yōu)性能,js引擎較一般編譯器更復(fù)雜,現(xiàn)在就讓來(lái)看js的編譯過(guò)程,簡(jiǎn)單的以編譯var a = 2為例:
詞法作用域
作用域一般有兩種工作模型,第一種是被大多數(shù)編程語(yǔ)言所采用的詞法作用域,另外一種叫作動(dòng)態(tài)作用域,如Bash腳本采用的就是動(dòng)態(tài)作用域。詞法作用域就是定義在詞法階段的作用域,詞法作用域是由你在寫(xiě)代碼時(shí)將變量和塊作用域?qū)懺谀睦飦?lái)決定的,由變量定義位置決定,而動(dòng)態(tài)作用域則是由變量使用的位置來(lái)決定的。下面來(lái)看個(gè)例子:
function foo(a) { var b = a * 2; function bar(c) { console.log(a, b, c) } bar(b * 3) } foo(2)
首先來(lái)分析一下這里一共存在幾個(gè)作用域?
接下來(lái)再來(lái)分析一下變量的查找過(guò)程,引擎執(zhí)行console.log()需要查找a、b、c三個(gè)變量的引用,首先從最里面的bar()作用域開(kāi)始找,引擎無(wú)法找到a,因此會(huì)再往上到foo()作用域中找,在這里找到了a,停止查找,對(duì)于b、c來(lái)說(shuō)查找過(guò)程一樣。作用域查找始終從運(yùn)行時(shí)最內(nèi)層開(kāi)始查找,逐級(jí)向外查找,直到遇見(jiàn)第一個(gè)匹配的變量為止。
函數(shù)作用域
函數(shù)作用域指的是屬于這個(gè)函數(shù)的全部變量都可以在整個(gè)函數(shù)的范圍內(nèi)使用及復(fù)用,這是大家都知道的定義,但是函數(shù)作用域的存在到底有什么用呢?接下來(lái)就一起看看函數(shù)作用域的秒用。
隱藏內(nèi)部實(shí)現(xiàn)
隱藏內(nèi)部實(shí)現(xiàn)就是將變量和函數(shù)包裹在一個(gè)函數(shù)的作用域中,達(dá)到隱藏的目的,為什么要這么做呢?軟件設(shè)計(jì)中有一個(gè)非常有名的原則叫最小暴露原則,指最小限度暴露必要內(nèi)容,而將其他內(nèi)容都隱藏起來(lái),比如模塊或?qū)ο蟮腁PI設(shè)計(jì)。用函數(shù)作用域來(lái)包裹變量和函數(shù)來(lái)達(dá)到最小暴露原則,阻止外部直接訪問(wèn),來(lái)看下面的例子:
function doSomething(a) { b = a + doSomethingElse( a * 2 ); console.log( b * 3 ); } function doSomethingElse(a) { return a - 1; } var b; doSomething( 2 ); // 15”
在這段代碼中doSomethingElse和b應(yīng)該是doSomething內(nèi)部私有的,但是卻被暴露出來(lái),這樣會(huì)導(dǎo)致以預(yù)期之外的形式被使用,產(chǎn)生意料之外的結(jié)果,更合理的設(shè)計(jì)應(yīng)該是將這些私有的內(nèi)容隱藏在doSomething內(nèi)部,例如:
function doSomething(a) { function doSomethingElse(a) { return a - 1; } var b; b = a + doSomethingElse( a * 2 ); console.log( b * 3 ); } doSomething( 2 );
這樣b和doSomethingElse都無(wú)法從doSomething外部訪問(wèn),但是這樣也會(huì)存在一些問(wèn)題,首先在全局作用域中聲明了doSomething函數(shù),污染了全局作用,其次,必須通過(guò)顯示調(diào)用才能執(zhí)行,那么有沒(méi)有什么辦法既不會(huì)污染作用域也不需要調(diào)用就可以自執(zhí)行呢?答案就是函數(shù)表達(dá)式,看下面的例子:
(function doSomething(a) { function doSomethingElse(a) { return a - 1; } var b; b = a + doSomethingElse( a * 2 ); console.log( b * 3 ); })(2)
首先來(lái)看(function doSomething(){})這是一個(gè)函數(shù)表達(dá)式,和函數(shù)聲明不同的是用括號(hào)包起來(lái)的,然后再(function doSomething(a){})()調(diào)用傳值,這樣既能自執(zhí)行也不會(huì)污染作用域,社區(qū)給這種用法定義了一個(gè)術(shù)語(yǔ):IIFE,代表立即執(zhí)行函數(shù)表達(dá)式
塊作用域
除JavaScript外很多編程語(yǔ)言都支持塊作用域,盡管你可能寫(xiě)過(guò)很偽塊作用域形式的代碼,最常見(jiàn)的就是for循環(huán):
for(var i=0; i<10; i++) { console.log(i) }
寫(xiě)這段代碼通常是希望變量i在循環(huán)內(nèi)部使用,但是實(shí)際上i會(huì)被綁定到外部作用域中,要確保沒(méi)有在作用域的其他地方意外使用i,就只能依靠自覺(jué),這時(shí)候塊級(jí)作用域就顯得尤為有用,ES6改變了現(xiàn)狀,引入了新的let、const關(guān)鍵字,let關(guān)鍵字可以將變量綁定到所在的任意作用域中,也就是let為其聲明的變量隱式地創(chuàng)建了作用域:
for(let i=0; i<10; i++) { console.log(i) } console.log(i) // ReferenceError
這時(shí)候i就只會(huì)在for循環(huán)的內(nèi)部有效
關(guān)于JavaScript中關(guān)于作用域的詳細(xì)介紹就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。