您好,登錄后才能下訂單哦!
這篇文章主要介紹javascript作用域鏈與執(zhí)行環(huán)境的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
作用域、作用域鏈、執(zhí)行環(huán)境、執(zhí)行環(huán)境棧以及this的概念在javascript中非常重要,本人經(jīng)常弄混淆,這里梳理一下;
局部作用域函數(shù)內(nèi)部的區(qū)域,全局作用域就是window;
作用域鏈取決于函數(shù)被聲明時(shí)的位置,解析標(biāo)識符的時(shí)候就先找當(dāng)前作用域,再向外查找,直到全局,這樣一個(gè)順序;和函數(shù)在哪里調(diào)用無關(guān);
執(zhí)行環(huán)境就是函數(shù)可訪問的數(shù)據(jù)和變量的集合,也就是函數(shù)的作用域鏈上的所有數(shù)據(jù)和變量;
執(zhí)行環(huán)境棧就是根據(jù)代碼執(zhí)行順序,各執(zhí)行環(huán)境按照棧的形式逐層訪問,并且用完了退出來扔掉;如果當(dāng)前執(zhí)行環(huán)境(存放當(dāng)前作用域鏈里的數(shù)據(jù)和變量)找不到變量,那就是找不到了,不會往之前的那個(gè)執(zhí)行環(huán)境查找,它和作用域鏈?zhǔn)遣煌模?/p>
this是一個(gè)對象,它取決于是誰執(zhí)行的,誰執(zhí)行那就是誰;(this的概念還是不太清楚,這里寫的有點(diǎn)萬金油,過兩天再來修正)
作用域
JavaScript沒有塊級作用域的概念,只有函數(shù)級作用域:變量在聲明它們的函數(shù)體及其子函數(shù)內(nèi)是可見的。
作用域就是變量和函數(shù)的可訪問范圍,控制著變量和函數(shù)的可見性與生命周期,在JavaScript中變量的作用域有全局作用域和局部作用域。
變量沒有在函數(shù)內(nèi)聲明或者聲明的時(shí)候沒有帶var就是全局變量,擁有全局作用域;
<script type="text/javascript"> function test1(){ a = 1;//全局變量,只有在當(dāng)前函數(shù)運(yùn)行時(shí),才有效 } test1(); console.log(a);//1 注意test1函數(shù)必須運(yùn)行,不然找不到a </script>
全局變量可以當(dāng)做window對象的屬性用,他們是一樣的;
<script type="text/javascript"> var b = 1;//全局變量 console.log(b === window.b);//true 全局變量可以當(dāng)做window對象的屬性用,他們是一樣的; </script>
window對象的所有屬性擁有全局作用域,在代碼任何地方都可以訪問;
函數(shù)內(nèi)部聲明的變量就是局部變量,只能在函數(shù)體內(nèi)使用,函數(shù)的參數(shù)雖然沒有使用var但仍然是局部變量。
<script type="text/javascript"> var c = 1;//全局變量 // console.log(d);//ReferenceError: d is not defined 引用錯(cuò)誤,當(dāng)前作用域就是最外層作用域,依然找不到d function test2(d){ console.log(c);//1 全局變量,哪都可以訪問;(先找當(dāng)前作用域,找不到,就向外層作用域找,直到window最外層,找到了) console.log(d);//3 形參是局部變量,只有當(dāng)前作用域下可以訪問 } test2(3); </script>
作用域鏈
作用域鏈取決于函數(shù)被聲明時(shí)的位置,解析標(biāo)識符的時(shí)候就先從當(dāng)前作用域開始找,在當(dāng)前作用域中無法找到時(shí),引擎就會在外層嵌套的作用域中繼續(xù)查找,直到找到該變量,或抵達(dá)最外層的作用域(也就是全局作用域)為止;它的路線已經(jīng)被定死了,和函數(shù)在哪里運(yùn)行無關(guān);
<script type="text/javascript"> var a = 1; var b = 2; var c = 3; var d = 4; function inner(d) {//它的作用域鏈?zhǔn)莍nner---全局 var c = 8; console.log(a);//1 當(dāng)前作用域找不到a,去全局作用域找到了a=1 console.log(b);//2 當(dāng)前作用域找不到b,去全局作用域找到了b=2 console.log(c);//8 當(dāng)前作用域找到了c=8 console.log(d);//7 當(dāng)前作用域找到了d=7,形參也是局部作用域 // console.log(e);//ReferenceError: e is not defined 引用錯(cuò)誤,找不到e, 它的作用域鏈?zhǔn)莍nner---全局 console.log(a+b+c+d);//18 } function outter(e) { var a = 5;//inner()的作用域鏈?zhǔn)莍nner---全局,所以這個(gè)a相當(dāng)于無效 var b = 6;//inner()的作用域鏈?zhǔn)莍nner---全局,所以這個(gè)a相當(dāng)于無效 inner(7); } outter(999);//這個(gè)999無效,里面的e根本找不到 </script>
在多層的嵌套作用域中可以定義同名的標(biāo)識符,這叫作“遮蔽效應(yīng)”,內(nèi)部的標(biāo)識符“遮蔽”了外部的標(biāo)識符
通過window.a這種技術(shù)可以訪問那些被同名變量所遮蔽的全局變量。但非全局的變量如果被遮蔽了,無論如何都無法被訪問到;
<script type="text/javascript"> var a = 'Lily'; var b = 'Lucy'; function outer() { var b = 'Jesica'; var c = 'Susan'; function inner(c) { console.log(a);//Lily console.log(window.b);//Lucy console.log(b);//Jesica console.log(c);//Jenifer } inner('Jenifer'); } outer(); </script>
執(zhí)行環(huán)境
執(zhí)行環(huán)境(execution context),也叫執(zhí)行上下文。每個(gè)執(zhí)行環(huán)境都有一個(gè)變量對象(variable object),保存函數(shù)可訪問的所有變量和數(shù)據(jù)(也就是函數(shù)的作用域鏈上的所有數(shù)據(jù)和變量)。我們的代碼訪問不到它,它是給引擎使用的;
執(zhí)行環(huán)境棧,當(dāng)執(zhí)行進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的執(zhí)行環(huán)境就會被推入一個(gè)棧中。而在函數(shù)執(zhí)行完之后,棧將其執(zhí)行環(huán)境移除,它里面的變量和數(shù)據(jù)會被標(biāo)記清除,等待垃圾回收,再把控制權(quán)返回給之前的執(zhí)行環(huán)境。javascript程序中的執(zhí)行正是由這個(gè)機(jī)制控制著;
需要注意的是如果當(dāng)前執(zhí)行環(huán)境(存放當(dāng)前作用域鏈里的數(shù)據(jù)和變量)找不到變量,那就是找不到了,不會往之前的那個(gè)執(zhí)行環(huán)境查找,和作用域鏈?zhǔn)遣灰粯拥模?/strong>
代碼的執(zhí)行順序也不全是一行一行的執(zhí)行,而是和函數(shù)的調(diào)用順序有關(guān):
代碼進(jìn)入全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境放入環(huán)境棧;
當(dāng)執(zhí)行到一個(gè)函數(shù)時(shí),就把這個(gè)函數(shù)的執(zhí)行環(huán)境推入到環(huán)境棧頂端,之前的執(zhí)行環(huán)境往后;
全局執(zhí)行環(huán)境最先進(jìn)入,所以一直在底端;就和棧的概念差不多;
函數(shù)執(zhí)行完之后,再把它的執(zhí)行環(huán)境從作用域鏈頂端移除,它保存的數(shù)據(jù)和函數(shù)都被標(biāo)記清除,等待垃圾回收;
控制權(quán)交給之前的執(zhí)行環(huán)境,繼續(xù)往下執(zhí)行;
當(dāng)頁面關(guān)閉時(shí),全局執(zhí)行環(huán)境才銷毀;
<script type="text/javascript"> var a = 1; var b = 2; var c = 3; var d = 4; function inner(d) {//它的作用域鏈?zhǔn)莍nner---全局 var c = 8; console.log(a);//1 當(dāng)前作用域找不到a,去全局作用域找到了a=1 console.log(b);//2 當(dāng)前作用域找不到b,去全局作用域找到了b=2 console.log(c);//8 當(dāng)前作用域找到了c=8 console.log(d);//7 當(dāng)前作用域找到了d=7,形參也是局部作用域 // console.log(e);//ReferenceError: e is not defined 引用錯(cuò)誤,找不到e, 它的作用域鏈?zhǔn)莍nner---全局 console.log(a+b+c+d);//18 } function outter(e) { var a = 5;//inner()的作用域鏈?zhǔn)莍nner---全局,所以這個(gè)a相當(dāng)于無效 var b = 6;//inner()的作用域鏈?zhǔn)莍nner---全局,所以這個(gè)a相當(dāng)于無效 inner(7); } outter(999);//這個(gè)999無效,里面的e根本找不到 </script>
以上代碼的執(zhí)行順序:
代碼執(zhí)行進(jìn)入全局執(zhí)行環(huán)境,并對全局執(zhí)行環(huán)境中的代碼進(jìn)入聲明提升;
執(zhí)行第2行,賦值a=1; 然后第3行賦值b=2; 然后第4行賦值c=3; 然后第5行賦值d=4;
執(zhí)行第20行,調(diào)用outer(999)函數(shù),然后進(jìn)入outer(999)函數(shù)執(zhí)行環(huán)境,聲明提升,并將實(shí)參999傳給形參e;現(xiàn)在環(huán)境棧中有兩個(gè)執(zhí)行環(huán)境,outer(999)是當(dāng)前執(zhí)行環(huán)境;
執(zhí)行第16行,賦值a=5; 然后第17行賦值b=6;
執(zhí)行第18行,調(diào)用inner(7)函數(shù),然后進(jìn)入inner(7)函數(shù)執(zhí)行環(huán)境,聲明提升,并將實(shí)參7傳給形參d;
執(zhí)行第7行,賦值c=8; 然后運(yùn)算并輸出;
代碼優(yōu)化
由于在作用域鏈上查找變量是需要消耗性能的,我們應(yīng)該盡快的找到變量,所以在函數(shù)多層嵌套的時(shí)候,我們應(yīng)盡可能的使用函數(shù)內(nèi)部的局部變量;
我們在函數(shù)內(nèi)部使用全局變量可以說是一種跨作用域操作,如果某個(gè)跨作用域的值在函數(shù)的內(nèi)部被多次使用,那么我們就把它存儲到局部變量里,這樣可以提高性能。
以上是“javascript作用域鏈與執(zhí)行環(huán)境的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。