摘要:經典面試題變量提升執(zhí)行環(huán)境作用域鏈今天記錄一個的經典面試題,該編程題涉及到了的變量提升執(zhí)行環(huán)境作用域鏈問題。這樣,一致延續(xù)到全局執(zhí)行環(huán)境全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。
js經典面試題--變量提升、執(zhí)行環(huán)境、作用域鏈
今天記錄一個js的經典面試題,該編程題涉及到了js的變量提升、執(zhí)行環(huán)境、作用域鏈問題。
1、變量提升
js沒有塊級作用域,使用var聲明的變量會自動添加到最接近的環(huán)境中。在函數內部,最接近的環(huán)境就是函數的局部環(huán)境。如果初始化變量時沒有使用var變量,該變量會自動被添加到全局環(huán)境。下面兩幅圖是等價的,結果都是控制臺打印出1 2 3 4 5
2、 執(zhí)行環(huán)境
每個函數都有自己的執(zhí)行環(huán)境。當執(zhí)行流進入一個函數時(即調用該函數),函數的環(huán)境就會被推入一個環(huán)境棧中。而在函數執(zhí)行之后,將其環(huán)境彈出棧,把控制權返回給之前的執(zhí)行環(huán)境。全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境。全局執(zhí)行環(huán)境被認為是window對象,全局執(zhí)行環(huán)境直到應用程序退出--例如關閉網頁或瀏覽器---時才會被銷毀。
function a(){ //執(zhí)行a功能代碼 } a(); //函數a的環(huán)境被推入一個環(huán)境棧中。 function b(){ //執(zhí)行b功能代碼 var c=function(){ //執(zhí)行c功能代碼 function d(){ //執(zhí)行d功能代碼 } retrun d(); } return c(); } b(); //函數b、c、d依次被推入一個環(huán)境棧中,當調用b()函數時,其依次被彈出
其執(zhí)行的具體流程如下圖所示:
3、作用域鏈
當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。作用域鏈中的下一個變量對象來自包含(外部)環(huán)境,而再下一個變量對象則來自下一個包含環(huán)境。這樣,一致延續(xù)到全局執(zhí)行環(huán)境;全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。
var a=1; function b(){ //執(zhí)行b功能代碼 var bVar=1; var c=function(){ //執(zhí)行c功能代碼 var cVar=2; function d(){ //執(zhí)行d功能代碼 var dVar=3; cVar=3; } retrun d(); } return c(); } b();
以上代碼共涉及4個執(zhí)行環(huán)境:全局環(huán)境,b()的局部環(huán)境、c()的局部環(huán)境、d()的局部環(huán)境。全局環(huán)境有一個變量a和一個函數b()。b()的局部環(huán)境中有一個變量bVar和一個函數c.....依次。位于最里邊的函數可以訪問外部環(huán)境的所有變量和函數,因為外部環(huán)境是它的父執(zhí)行環(huán)境。總結:內部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境無法訪問到內部環(huán)境中的任何變量和函數。這些環(huán)境之間的聯(lián)系是線性、有次序的。每個環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數名(服從就近原則);但任何環(huán)境都不能通過向下搜索作用域而進入另一個執(zhí)行環(huán)境。
通過上面介紹執(zhí)行環(huán)境與作用域的兩幅圖可以看出,瀏覽器在執(zhí)行js時,首先會將window對象(全局執(zhí)行環(huán)境)壓入環(huán)境棧,每次執(zhí)行一個函數時,被調用的函數(按照調用的先后順序)依次壓入環(huán)境棧中。而壓入棧中的環(huán)境類似于容器,往棧底方向的容器包含了上面的容器。容器中存放的是自己的變量和函數以及上面的容器。我們可以把容器的玻璃的材質想象為車窗戶(可以從里邊看到外面,但是無法從外面看到里邊),當在某個環(huán)境(容器)中執(zhí)行代碼塊時,就好比我們站在當前容器里,此時我們可以看到外部容器(父級環(huán)境)的變量和函數,但卻看不到內部容器的任何東西,這就是作用域鏈。
下面進入正題,說下我對該面試題的理解
1 var foo = {n:1}; 2 (function (foo) { 3 console.log(foo.n); 4 foo.n=3; 5 var foo = {n:2}; 6 console.log(foo.n); 7 })(foo); 8 console.log(foo.n);
上面的代碼其實可以寫成這樣:
1 var foo = {n:1}; 2 (function (foo) { 3 var foo; 4 console.log(foo.n); 5 foo.n=3; 6 var foo = {n:2}; 7 console.log(foo.n); 8 })(foo); 9 console.log(foo.n);
1、聲明一個變量,為引用類型
2和8、聲明一個匿名函數,并立即執(zhí)行,傳遞的參數是第1行中的foo。將一個對象類型賦值給一個新的變量,由于對象是引用類型,實質上是指將對象的地址賦值給該變量(也就是說這兩個變量指向同一個地址空間),因此改變新的變量中的屬性值或方法,對應的原來對象的值也會改變。
3、原題中的第5行,由于存在變量提升,因此會在函數開始就聲明,此時為undefined;然而由于一個變量的聲明優(yōu)先級低于形參,所以這行沒有任何效果
4、打印形參的foo.n,打印1
5、改變第1行變量foo的屬性n的值為3;
6、重新聲明并定義了一個變量,開辟了新的內存空間,n為2
7、由于js中的代碼是自上而下執(zhí)行,所以此時輸出2
9、上面的函數調用結束后,局部變量被銷毀,而之前的內存空間值已經變?yōu)?,所以輸出3
所以最終的結果為:1 2 3
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94349.html
摘要:本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。網頁的行為層負責回答內容應該如何對事件做出反應這一問題。 本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。眼看新的一年馬上就要開始了,相信很多的前端開發(fā)者會有一些跳槽的悸動,通過對本篇知識的整理以及經驗的總結,希望能幫到更多的前端面試者。(如有錯誤或更好的答案,歡迎指正,水平有限,望...
摘要:本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。網頁的行為層負責回答內容應該如何對事件做出反應這一問題。 本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。眼看新的一年馬上就要開始了,相信很多的前端開發(fā)者會有一些跳槽的悸動,通過對本篇知識的整理以及經驗的總結,希望能幫到更多的前端面試者。(如有錯誤或更好的答案,歡迎指正,水平有限,望...
摘要:本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。網頁的行為層負責回答內容應該如何對事件做出反應這一問題。 本篇收錄了一些面試中經常會遇到的經典面試題,并且都給出了我在網上收集的答案。眼看新的一年馬上就要開始了,相信很多的前端開發(fā)者會有一些跳槽的悸動,通過對本篇知識的整理以及經驗的總結,希望能幫到更多的前端面試者。(如有錯誤或更好的答案,歡迎指正,水平有限,望...
摘要:引言滿滿的干貨,面試必系列,參考大量資料,并集合自己的理解以及相關的面試題,對核心知識點中的作用域閉包上下文進行了梳理。如果在小區(qū)這個作用域找到了張老師,我就會在張老師的輔導下學鋼琴我張老師房間鋼琴構成了學琴的上下文環(huán)境。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 滿滿的干貨,面試必bei系列,參考大...
閱讀 991·2021-11-23 09:51
閱讀 3479·2021-11-22 12:04
閱讀 2723·2021-11-11 16:55
閱讀 2941·2019-08-30 15:55
閱讀 3232·2019-08-29 14:22
閱讀 3358·2019-08-28 18:06
閱讀 1247·2019-08-26 18:36
閱讀 2132·2019-08-26 12:08