国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

前端進階(六):觀察函數調用棧、作用域鏈與閉包

來源:懂視網 責編:小采 時間:2020-11-27 20:23:09
文檔

前端進階(六):觀察函數調用棧、作用域鏈與閉包

前端進階(六):觀察函數調用棧、作用域鏈與閉包:配圖與本文無關在前端開發中,有一個非常重要的技能,叫做斷點調試。在chrome的開發者工具中,通過斷點調試,我們能夠非常方便的一步一步的觀察JavaScript的執行過程,直觀感知函數調用棧,作用域鏈,變量對象,閉包,this等關鍵信息的變化。因此,斷點調試對
推薦度:
導讀前端進階(六):觀察函數調用棧、作用域鏈與閉包:配圖與本文無關在前端開發中,有一個非常重要的技能,叫做斷點調試。在chrome的開發者工具中,通過斷點調試,我們能夠非常方便的一步一步的觀察JavaScript的執行過程,直觀感知函數調用棧,作用域鏈,變量對象,閉包,this等關鍵信息的變化。因此,斷點調試對
一、基礎概念回顧

函數在被調用執行時,會創建一個當前函數的執行上下文。在該執行上下文的創建階段,變量對象、作用域鏈、閉包、this指向會分別被確定。而一個JavaScript程序中一般來說會有多個函數,JavaScript引擎使用函數調用棧來管理這些函數的調用順序。函數調用棧的調用順序與棧數據結構一致。

二、認識斷點調試工具

在盡量新版本的chrome瀏覽器中(不確定你用的老版本與我的一致),調出chrome瀏覽器的開發者工具。

瀏覽器右上角豎著的三點 -> 更多工具 -> 開發者工具 -> Sources

界面如圖。


斷點調試界面

在我的demo中,我把代碼放在app.js中,在index.html中引入。我們暫時只需要關注截圖中紅色箭頭的地方。在最右側上方,有一排圖標。我們可以通過使用他們來控制函數的執行順序。從左到右他們依次是:

  • resume/pause script execution
    恢復/暫停腳本執行

  • step over next function call
    跨過,實際表現是不遇到函數時,執行下一步。遇到函數時,不進入函數直接執行下一步。

  • step into next function call
    跨入,實際表現是不遇到函數時,執行下一步。遇到到函數時,進入函數執行上下文。

  • step out of current function
    跳出當前函數

  • deactivate breakpoints
    停用斷點

  • don‘t pause on exceptions
    不暫停異常捕獲

  • 其中跨過,跨入,跳出是我使用最多的三個操作。

    上圖右側第二個紅色箭頭指向的是函數調用棧(call Stack),這里會顯示代碼執行過程中,調用棧的變化。

    右側第三個紅色箭頭指向的是作用域鏈(Scope),這里會顯示當前函數的作用域鏈。其中Local表示當前的局部變量對象,Closure表示當前作用域鏈中的閉包。借助此處的作用域鏈展示,我們可以很直觀的判斷出一個例子中,到底誰是閉包,對于閉包的深入了解具有非常重要的幫助作用。

    三、斷點設置

    在顯示代碼行數的地方點擊,即可設置一個斷點。斷點設置有以下幾個特點:

  • 在單獨的變量聲明(如果沒有賦值),函數聲明的那一行,無法設置斷點。

  • 設置斷點后刷新頁面,JavaScript代碼會執行到斷點位置處暫停執行,然后我們就可以使用上邊介紹過的幾個操作開始調試了。

  • 當你設置多個斷點時,chrome工具會自動判斷從最早執行的那個斷點開始執行,因此我一般都是設置一個斷點就行了。

  • 四、實例

    接下來,我們借助一些實例,來使用斷點調試工具,看一看,我們的demo函數,在執行過程中的具體表現。

    // demo01
    
    var fn;
    function foo() {
     var a = 2;
     function baz() { 
     console.log( a );
     }
     fn = baz; 
    }
    function bar() {
     fn(); 
    }
    
    foo();
    bar(); // 2

    在向下閱讀之前,我們可以停下來思考一下,這個例子中,誰是閉包?

    這是來自《你不知道的js》中的一個例子。由于在使用斷點調試過程中,發現chrome瀏覽器理解的閉包與該例子中所理解的閉包不太一致,因此專門挑出來,供大家參考。我個人更加傾向于chrome中的理解。

  • 第一步:設置斷點,然后刷新頁面。


  • 設置斷點

  • 第二步:點擊上圖紅色箭頭指向的按鈕(step into),該按鈕的作用會根據代碼執行順序,一步一步向下執行。在點擊的過程中,我們要注意觀察下方call stack 與 scope的變化,以及函數執行位置的變化。

  • 一步一步執行,當函數執行到上例子中


    baz函數被調用執行,foo形成了閉包

    我們可以看到,在chrome工具的理解中,由于在foo內部聲明的baz函數在調用時訪問了它的變量a,因此foo成為了閉包。這好像和我們學習到的知識不太一樣。我們來看看在《你不知道的js》這本書中的例子中的理解。


    你不知道的js中的例子

    書中的注釋可以明顯的看出,作者認為fn為閉包。即baz,這和chrome工具中明顯是不一樣的。

    而在備受大家推崇的《JavaScript高級編程》一書中,是這樣定義閉包。


    JavaScript高級編程中閉包的定義


    書中作者將自己理解的閉包與包含函數所區分

    這里chrome中理解的閉包,與我所閱讀的這幾本書中的理解的閉包不一樣。具體這里我先不下結論,但是我心中更加偏向于相信chrome瀏覽器。

    我們修改一下demo01中的例子,來看看一個非常有意思的變化。

    // demo02
    var fn;
    var m = 20;
    function foo() {
     var a = 2;
     function baz(a) { 
     console.log(a);
     }
     fn = baz; 
    }
    function bar() {
     fn(m); 
    }
    
    foo();
    bar(); // 20

    這個例子在demo01的基礎上,我在baz函數中傳入一個參數,并打印出來。在調用時,我將全局的變量m傳入。輸出結果變為20。在使用斷點調試看看作用域鏈。


    閉包沒了,作用域鏈中沒有包含foo了。

    是不是結果有點意外,閉包沒了,作用域鏈中沒有包含foo了。我靠,跟我們理解的好像又有點不一樣。所以通過這個對比,我們可以確定閉包的形成需要兩個條件。

  • 在函數內部創建新的函數;

  • 新的函數在執行時,訪問了函數的變量對象;

  • 還有更有意思的。

    我們繼續來看看一個例子。

    // demo03
    
    function foo() {
     var a = 2;
    
     return function bar() {
     var b = 9;
    
     return function fn() {
     console.log(a);
     }
     }
    }
    
    var bar = foo();
    var fn = bar();
    fn();

    在這個例子中,fn只訪問了foo中的a變量,因此它的閉包只有foo。


    閉包只有foo

    修改一下demo03,我們在fn中也訪問bar中b變量試試看。

    // demo04
    
    function foo() {
     var a = 2;
    
     return function bar() {
     var b = 9;
    
     return function fn() {
     console.log(a, b);
     }
     }
    }
    
    var bar = foo();
    var fn = bar();
    fn();


    這個時候閉包變成了兩個

    這個時候,閉包變成了兩個。分別是bar,foo。

    我們知道,閉包在模塊中的應用非常重要。因此,我們來一個模塊的例子,也用斷點工具來觀察一下。

    // demo05
    (function() {
    
     var a = 10;
     var b = 20;
    
     var test = {
     m: 20,
     add: function(x) {
     return a + x;
     },
     sum: function() {
     return a + b + this.m;
     },
     mark: function(k, j) {
     return k + j;
     }
     }
    
     window.test = test;
    
    })();
    
    test.add(100);
    test.sum();
    test.mark();
    
    var _mark = test.mark;
    _mark();


    add執行時,閉包為外層的自執行函數,this指向test


    sum執行時,同上


    mark執行時,閉包為外層的自執行函數,this指向test


    _mark執行時,閉包為外層的自執行函數,this指向window

    注意:這里的this指向顯示為Object或者Window,大寫開頭,他們表示的是實例的構造函數,實際上this是指向的具體實例

    test.mark能形成閉包,跟下面的補充例子(demo07)情況是一樣的。

    我們還可以結合點斷調試的方式,來理解那些困擾我們很久的this指向。隨時觀察this的指向,在實際開發調試中非常有用。

    // demo06
    
    var a = 10;
    var obj = {
     a: 20
    }
    
    function fn () {
     console.log(this.a);
    }
    
    fn.call(obj); // 20


    this指向obj

    補充一個例子

    // demo07
    function foo() {
     var a = 10;
    
     function fn1() {
     return a;
     }
    
     function fn2() {
     return 10;
     }
    
     fn2();
    }
    
    foo();

    這個例子,和其他例子不太一樣。雖然fn2并沒有訪問到foo的變量,但是foo執行時仍然變成了閉包。而當我將fn1的聲明去掉時,閉包便不會出現了。我暫時也不知道應該如何解釋這種情況。只能大概知道與fn1有關,可能瀏覽器在實現時就認為只要存在訪問上層作用域的可能性,就會被當成一個閉包吧。所以暫時就只能將它作為一個特例記住。

    更多的例子,大家可以自行嘗試,總之,學會了使用斷點調試之后,我們就能夠很輕松的了解一段代碼的執行過程了。這對快速定位錯誤,快速了解他人的代碼都有非常巨大的幫助。大家一定要動手實踐,把它給學會。

    最后,根據以上的摸索情況,再次總結一下閉包:

  • 閉包是在函數被調用執行的時候才被確認創建的。

  • 閉包的形成,與作用域鏈的訪問順序有直接關系。

  • 只有內部函數訪問了上層作用域鏈中的變量對象時,才會形成閉包,因此,我們可以利用閉包來訪問函數內部的變量。

  • chrome中理解的閉包,與《你不知道的js》與《JavaScript高級編程》中的閉包理解有很大不同,我個人更加傾向于相信chrome。這里就不妄下結論了,大家可以根據我的思路,探索后自行確認。在之前一篇文中我根據從書中學到的下了定義,應該是錯了,目前已經修改,對不起大家了。

  • 大家也可以根據我提供的這個方法,對其他的例子進行更多的測試,如果發現我的結論有不對的地方,歡迎指出,大家相互學習進步,謝謝大家。

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    前端進階(六):觀察函數調用棧、作用域鏈與閉包

    前端進階(六):觀察函數調用棧、作用域鏈與閉包:配圖與本文無關在前端開發中,有一個非常重要的技能,叫做斷點調試。在chrome的開發者工具中,通過斷點調試,我們能夠非常方便的一步一步的觀察JavaScript的執行過程,直觀感知函數調用棧,作用域鏈,變量對象,閉包,this等關鍵信息的變化。因此,斷點調試對
    推薦度:
    標簽: 作用 進階 ):
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 福利视频一区二区 | 亚洲一区 中文字幕 久久 | 免费国产高清视频 | 精品不卡| 亚洲欧美日韩另类在线专区 | 精品国产成人综合久久小说 | 欧美一级专区免费大片 | 在线观看国产亚洲 | 男女男精品网站 | 国内精品线在线观看 | 国产一区二区精品久久91 | 日韩高清专区 | 久久久久777777人人人视频 | 国产精品成人va | 欧美理论电影在线观看 | 欧美一区二区三区四区视频 | 国产精品久久久久久久专区 | 亚洲精品国产综合一线久久 | 久久一区二区精品综合 | 国产夫妻精品 | 国产一区在线看 | 九九精品视频一区在线 | 国内精品1区1区3区4区 | 亚洲永久精品一区二区三区 | 曰韩三级| 国产在线精品一区二区三区不卡 | 中文字幕美日韩在线高清 | 国产精品久久久久久久久久久久 | 欧美日本道免费一区二区三区 | 麻豆精品国产 | 91久久精品一区二区三区 | 一区二区三区电影 | 国内一级片 | 欧美一区二区在线 | 国产精品久久久久久一区二区 | 成人亚洲欧美日韩在线 | 国产精品va在线观看无 | 欧美一区二区在线 | 国产区精品在线 | 亚洲第一欧美 | 亚洲欧美一区二区三区九九九 |