亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

全面了解JavaScript的作用域鏈

2024-05-06 16:49:33
字體:
來源:轉載
供稿:網友
JavaScript的作用域鏈

這是一個非常重要的知識點了,了解了JavaScript的作用域鏈的話,能幫助我們理解很多‘異常'問題。

下面我們來看一個小例子,前面我說過的聲明提前的例子。

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

 對于這個例子,沒有接觸過這方面的時候,第一反應是會糾結下,這第一個的name,到底調用全局變量的name,還是函數內部的name呢,如果調用全局的,可是函數內部也用定義和賦值啊, 如果調用函數內部的局部變量的話,那么他的值是mm嗎?還是引用全局的'Skylor.min'呢?

于是這個小例子就會有這樣的錯誤答案:

Skylor.min
mm
[腳本出錯]
 

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

    undefined
    mm
    [腳本出錯]
 

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

原理

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

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

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

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

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

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

看個例子吧:

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 >

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久久久久久久久ktv| 国产欧美一区二区三区在线| 国产主播在线一区| 国内精品久久久久影院 日本资源| 日韩av大片在线| 色偷偷888欧美精品久久久| 欧美日韩在线视频一区| 亚洲japanese制服美女| 91系列在线观看| 欧美性猛交xxxx免费看| 日韩精品在线观看一区二区| 国产精品激情av电影在线观看| 国模视频一区二区三区| 日韩av网址在线观看| 欧美综合第一页| 国产精品xxx视频| 日韩精品高清在线| 成人黄色在线观看| 91精品久久久久久久久久| 欧美极品在线播放| 欧美激情视频网站| 亚洲综合中文字幕68页| 亚洲91精品在线| www.欧美免费| 国产精品va在线播放我和闺蜜| 欧美极度另类性三渗透| 中文字幕欧美日韩在线| 91欧美日韩一区| 国产精品成人在线| 午夜精品一区二区三区视频免费看| 亲爱的老师9免费观看全集电视剧| 亚洲人成网站999久久久综合| 2018中文字幕一区二区三区| 国产亚洲精品一区二区| 欧美激情视频网站| 欧美高清激情视频| 亚洲日本欧美日韩高观看| 日本午夜人人精品| 日韩精品视频在线播放| 欧美网站在线观看| 成人av资源在线播放| 91在线国产电影| 狠狠色噜噜狠狠狠狠97| 亚洲aaa激情| 欧美激情一区二区三区在线视频观看| 日韩一区二区久久久| 色婷婷久久一区二区| 91香蕉嫩草神马影院在线观看| 国产一区玩具在线观看| 久久777国产线看观看精品| 美女扒开尿口让男人操亚洲视频网站| 国产成人精彩在线视频九色| 日韩欧美在线中文字幕| 亚洲国产精品va在线看黑人动漫| 91国内在线视频| www.日韩不卡电影av| 国产精品爽爽ⅴa在线观看| 欧美另类极品videosbest最新版本| 国产精品扒开腿爽爽爽视频| 亚洲一区第一页| 国产精品久久久久一区二区| 78m国产成人精品视频| 欧美激情女人20p| 国产欧美 在线欧美| 精品亚洲男同gayvideo网站| 国产成人在线一区二区| 日韩av免费在线播放| 午夜精品福利视频| 亚洲电影免费在线观看| 午夜精品久久久久久99热| 亚洲成人激情视频| 久久久久久国产精品三级玉女聊斋| 狠狠躁18三区二区一区| 日韩精品亚洲精品| 亚洲天堂2020| 日韩精品在线视频| 亚洲男人av电影| 中文字幕亚洲激情| 国产日韩在线看| 91高潮在线观看| 丝袜美腿亚洲一区二区| 久久久国产精品视频| 97成人精品区在线播放| 久久久精品免费视频| 亚洲一区二区免费在线| 国产精品jizz在线观看麻豆| 456亚洲影院| 茄子视频成人在线| 欧美性猛交99久久久久99按摩| 精品视频偷偷看在线观看| 国产成人精品视频| 91免费在线视频网站| 日韩经典第一页| 国产精品久久99久久| 成人午夜在线影院| 26uuu另类亚洲欧美日本老年| 97国产一区二区精品久久呦| 中文字幕日韩欧美在线视频| 亚洲精品永久免费| 韩国视频理论视频久久| 一区二区日韩精品| 4388成人网| 国产精品久久久精品| 国产亚洲精品一区二555| 一个人看的www久久| 亚洲free嫩bbb| 久久久亚洲影院你懂的| 欧美精品情趣视频| 91wwwcom在线观看| 日韩国产精品一区| 国产精品入口免费视频一| 美女撒尿一区二区三区| 亚洲精品资源美女情侣酒店| 亚洲自拍av在线| 国产欧美一区二区白浆黑人| 久热在线中文字幕色999舞| 在线视频精品一| 亚洲女性裸体视频| 亚洲午夜未删减在线观看| 国产一区二区三区视频免费| 国产精品电影久久久久电影网| 日韩av在线免费| 欧美日韩另类在线| 久青草国产97香蕉在线视频| 激情久久av一区av二区av三区| 综合激情国产一区| xvideos国产精品| 欧美国产视频一区二区| 国产精品自拍网| 91国内免费在线视频| 亚洲人高潮女人毛茸茸| 久久精品影视伊人网| 91国产美女在线观看| 欧美激情久久久久| 久久久国产精品亚洲一区| 久久精品国产亚洲| 久久久视频免费观看| 国产精品视频一区二区高潮| 色婷婷**av毛片一区| 懂色av中文一区二区三区天美| 欧美另类精品xxxx孕妇| 欧美小视频在线观看| 日韩有码在线观看| 国产91精品青草社区| 成人免费视频xnxx.com| 欧美亚洲另类制服自拍| 亚洲国产精品字幕| 91伊人影院在线播放| 日本中文字幕久久看| 亚洲最大av网| 日本三级韩国三级久久| 亚洲精品成a人在线观看| 国产精品一区二区av影院萌芽| 亚洲精品影视在线观看| 国产精品成人观看视频国产奇米| 中文字幕综合在线| 亚洲男人av电影| 9.1国产丝袜在线观看| 国产91露脸中文字幕在线| 亚洲一区二区在线播放| 亚洲国产一区二区三区在线观看| 亚洲精品福利视频| 精品国内亚洲在观看18黄| 久久国内精品一国内精品|