<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答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
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        全面了解JavaScript的作用域鏈

        來源:懂視網 責編:小采 時間:2020-11-27 21:59:25
        文檔

        全面了解JavaScript的作用域鏈

        全面了解JavaScript的作用域鏈:JavaScript的作用域鏈 這是一個非常重要的知識點了,了解了JavaScript的作用域鏈的話,能幫助我們理解很多異常'問題。 下面我們來看一個小例子,前面我說過的聲明提前的例子。 var name = 'Skylor.min'; function echo() { alert
        推薦度:
        導讀全面了解JavaScript的作用域鏈:JavaScript的作用域鏈 這是一個非常重要的知識點了,了解了JavaScript的作用域鏈的話,能幫助我們理解很多異常'問題。 下面我們來看一個小例子,前面我說過的聲明提前的例子。 var name = 'Skylor.min'; function echo() { alert

        其實不然,知道函數內的提前說明,就知道這是不正確的。

            undefined
            mm
            [腳本出錯]
         

        應該是這樣的,那到底為什么是這個答案呢,提前聲明這又是什么呢?一切的一切,涉及到JavaScript的作用域鏈。

        原理

        首先來說說,JavaScript的作用域的原理:

        在JavaScript權威指南中有一句很精辟的描述: JavaScript中的函數運行在它們被定義的作用域里,而不是它們被運行的作用域里。

        另外在JavaScript中有個很重要的概念,那就是: 在JavaScript中,一切皆對象,函數也是。

        在JS中,作用域的概念和其他語言差不多, 在每次調用一個函數的時候 ,就會進入一個函數內的作用域,當從函數返回以后,就返回調用前的作用域

        JS的語法風格和C/C++類似, 但作用域的實現卻和C/C++不同,并非用“堆棧”方式,而是使用列表,具體過程如下(ECMA262中所述):

      1. 任何執行上下文時刻的作用域, 都是由作用域鏈(scope chain, 后面介紹)來實現
      2. 在一個函數被定義的時候, 會將它定義時刻的scope chain鏈接到這個函數對象的[[scope]]屬性
      3. 在一個函數對象被調用的時候,會創建一個活動對象(也就是一個對象), 然后對于每一個函數的形參,都命名為該活動對象的命名屬性, 然后將這個活動對象做為此時的作用域鏈(scope chain)最前端, 并將這個函數對象的[[scope]]加入到scope chain中.
      4. 看個例子吧:

        var func = function(lps, rps){
                var name = 'Skylor.min';
                ........
            }
            func();
         

        在執行func的定義語句的時候, 會創建一個這個函數對象的[[scope]]屬性(內部屬性,只有JS引擎可以訪問, 但FireFox的幾個引擎(SpiderMonkey和Rhino)提供了私有屬性__parent__來訪問它), 并將這個[[scope]]屬性, 鏈接到定義它的作用域鏈上(后面會詳細介紹), 此時因為func定義在全局環境, 所以此時的[[scope]]只是指向全局活動對象window active object.

        在調用func的時候, 會創建一個活動對象(假設為aObj, 由JS引擎預編譯時刻創建, 后面會介紹),并創建arguments屬性, 然后會給這個對象添加倆個命名屬性aObj.lps, aObj.rps; 對于每一個在這個函數中申明的局部變量和函數定義, 都作為該活動對象的同名命名屬性.

        然后將調用參數賦值給形參數,對于缺少的調用參數,賦值為undefined。

        然后將這個活動對象做為scope chain的最前端, 并將func的[[scope]]屬性所指向的,定義func時候的頂級活動對象, 加入到scope chain.

        有了上面的作用域鏈, 在發生標識符解析的時候, 就會逆向查詢當前scope chain列表的每一個活動對象的屬性,如果找到同名的就返回。找不到,那就是這個標識符沒有被定義。

        注意到, 因為函數對象的[[scope]]屬性是在定義一個函數的時候決定的, 而非調用的時候, 所以如下面的例子:

        var name = 'Skylor.min';
         function echo() {
         alert(name);
         }
        
         function env() {
         var name = 'mm';
         echo();
         }
        
         env();

        他的運行結果是:Skylor.min

        結合上面的知識, 我們來看看下面這個例子,還記得那句JavaScript權威指南中的經典,JavaScript中的函數運行在它們被定義的作用域里,而不是它們被運行的作用域里。

        function factory() {
         var name = 'Skylor.min';
         var intro = function(){
         alert('I am ' + name);
         }
         return intro;
         }
        
         function app(para){
         var name = para;
         var func = factory();
         func();
         }
        
         app('mm');

        當調用app的時候, scope chain是由: {window活動對象(全局)}->{app的活動對象} 組成.

        在剛進入app函數體時, app的活動對象有一個arguments屬性, 其他倆個值為undefined的屬性: name和func. 和一個值為'mm'的屬性para;

        此時的scope chain如下:

        [[scope chain]] = [
         {
         para : 'mm',
         name : undefined,
         func : undefined,
         arguments : []
         }, {
         window call object
         }
         ]

         當調用進入factory的函數體的時候, 此時的factory的scope chain為:

        [[scope chain]] = [
         {
         name : undefined,
         intor : undefined
         }, {
         window call object
         }
         ]

        注意到, 此時的作用域鏈中, 并不包含app的活動對象.

        在定義intro函數的時候, intro函數的[[scope]]為:

        [[scope chain]] = [
         {
         name : 'Skylor.min',
         intor : undefined
         }, {
         window call object
         }
         ]

        從factory函數返回以后,在app體內調用intor的時候, 發生了標識符解析, 而此時的sope chain是:

        [[scope chain]] = [
         {
         intro call object
         }, {
         name : 'Skylor.min',
         intor : undefined
         }, {
         window call object
         }
         ]

         因為scope chain中,并不包含factory活動對象. 所以, name標識符解析的結果應該是factory活動對象中的name屬性, 也就是'Skylor.min'.

        所以運行結果是: I am Skylor.min

        至此,完整的一個運行流程,很清晰的能讀懂“JavaScript中的函數運行在它們被定義的作用域里,而不是它們被運行的作用域里。”這句話講的是什么了。

        為了解釋上面的一些問題,還得說說JavaScript的預編譯。

        JavaScriptの預編譯

        預編譯,學過C等的我們都知道,可是問題來了,JavaScript是腳本語言,JavaScript的執行過程是一種翻譯執行的過程,那在JavaScript的執行中,有沒有類似編譯的過程呢?

        如果不是很確定,先通過一個例子:

        alert(typeof fun); //function
            function fun() {
                alert('I am Skylor.min');
            };
         

        這時候彈出來的是?-----我去,是“I am Skylor.min”然而這時為什么呢,為啥不是undefined呢。

        恩, 對, 在JS中, 是有預編譯的過程的, JS在執行每一段JS代碼之前, 都會首先處理var關鍵字和function定義式(函數定義式和函數表達式).

        如上文所說, 在調用函數執行之前, 會首先創建一個活動對象, 然后搜尋這個函數中的局部變量定義,和函數定義, 將變量名和函數名都做為這個活動對象的同名屬性, 對于局部變量定義,變量的值會在真正執行的時候才計算, 此時只是簡單的賦為undefined.

        而對于函數的定義,是一個要注意的地方:

        alert(typeof fun); //結果:function
         alert(typeof fn); //結果:undefined
         function fun() { //函數定義式
         alert('I am Skylor.min');
         };
         var fn = function() { //函數表達式
         }
         alert(typeof fn); //結果:function

        這就是函數定義式和函數表達式的不同, 對于函數定義式, 會將函數定義提前. 而函數表達式, 會在執行過程中才計算.

        說到這里, 順便說一個問題 :

            var name = 'Skylor.min';
            age = 25;
         

        我們都知道不使用var關鍵字定義的變量, 相當于是全局變量, 聯系到我們剛才的知識:

        在對age做標識符解析的時候, 因為是寫操作, 所以當找到到全局的window活動對象的時候都沒有找到這個標識符的時候, 會在window活動對象的基礎上, 返回一個值為undefined的age屬性.

        也就是說, age會被定義在頂級作用域中.

        現在, 也許你注意到了我剛才說的: JS在執行每一段JS代碼之前, 都會首先處理var關鍵字和function定義式(函數定義式和函數表達式).

        對, 讓我們看看下面的例子:

        <script >
         alert(typeof mm); //結果:undefined
         </script >
         <script >
         function mm() {
         alert('I am Skylor.min');
         }
         </script >

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

        文檔

        全面了解JavaScript的作用域鏈

        全面了解JavaScript的作用域鏈:JavaScript的作用域鏈 這是一個非常重要的知識點了,了解了JavaScript的作用域鏈的話,能幫助我們理解很多異常'問題。 下面我們來看一個小例子,前面我說過的聲明提前的例子。 var name = 'Skylor.min'; function echo() { alert
        推薦度:
        標簽: 作用 js 了解
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 在线播放免费人成视频在线观看| 一级毛片视频免费观看| 91禁漫免费进入| 中文字幕在线亚洲精品| 青青草国产免费国产是公开| 国产在线观看免费视频播放器| 国产AV无码专区亚洲AV麻豆丫| 日韩免费观看一级毛片看看| 自拍偷自拍亚洲精品偷一| 免费人妻av无码专区| 国产精品免费久久| 亚洲伊人久久大香线蕉综合图片| 久久国产福利免费| 亚洲最大成人网色| 无码中文字幕av免费放| 亚洲精品无码一区二区| 免费人成年轻人电影| a级毛片无码免费真人久久| 亚洲一本综合久久| 日韩免费一区二区三区在线播放| 亚洲国产系列一区二区三区| 国产精品冒白浆免费视频| 成人a毛片视频免费看| 亚洲国产AV无码专区亚洲AV| 67pao强力打造高清免费| 亚洲日韩中文字幕无码一区| 亚洲国产精品尤物yw在线| 国产偷伦视频免费观看| 亚洲人成电影在线观看网| 男人的天堂亚洲一区二区三区 | 大地影院MV在线观看视频免费| 亚洲AV福利天堂一区二区三| 日韩免费a级毛片无码a∨ | 中文字幕在线免费看| 亚洲精品中文字幕无乱码| 国产免费av片在线无码免费看| 嫩草在线视频www免费看| 亚洲色丰满少妇高潮18p| av在线亚洲欧洲日产一区二区| 亚洲免费观看在线视频| 国产午夜亚洲精品不卡免下载|