欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript作用域鏈(Scope Chain)用法實例解析

 更新時間:2015年11月30日 10:44:13   作者:Jeff Wong  
這篇文章主要介紹了javascript作用域鏈(Scope Chain)用法,結(jié)合實例形式較為詳細(xì)的分析了javascript作用域鏈(Scope Chain)的概念、功能與相關(guān)使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下

本文實例分析了javascript作用域鏈(Scope Chain)用法。分享給大家供大家參考,具體如下:

關(guān)于js的作用域鏈,早有耳聞,也曾看過幾篇介紹性的博文,但一直都理解的模棱兩可。近日又精心翻看了一下《悟透Javascript》這本書,覺得寫得太深刻,在“代碼的時空”一節(jié)里有一段介紹作用域鏈的地方寥寥數(shù)語,回味無窮(其實還是理解的模棱兩可^_^)。現(xiàn)在整理下自己的讀書筆記,順便借鑒網(wǎng)上資源,寫下來。

一、從一個簡單的問題說起

下面的js代碼在頁面中運行顯示什么結(jié)果:

var arg = 1;
function fucTest(arg) {
  alert(arg);
  var arg = 2;
  //alert(arg);
}
fucTest(10);

您的答案是什么?沒錯,就是彈出10。我的理解是這樣的,funTest函數(shù)有一個形參arg,funTest函數(shù)傳入實參10,alert方法把10彈出就是了,囧。
好,問題又來了:

var arg = 1;
function funcTest() {
  alert(arg);
  var arg = 2;
}
arg = 10;
funcTest();

答案是什么?如果是5年前的我,肯定不會再往下想了,還是10!這么簡單的問題還用想什么呀?我的理解是這樣的:funTest函數(shù)是一個無參數(shù)的函數(shù),函數(shù)內(nèi)部通過alert方法,調(diào)用外部(全局)的變量arg,在函數(shù)執(zhí)行前,arg賦值為10,彈出arg值后改變arg值為2,所以彈出值為10。

真的是10嗎?是還是不是?

測試的結(jié)果:彈出“undefined”,瀑布汗.

二、理解作用域鏈,從javascript運行機制說起

1、js的運行順序

如果一個文檔流中包含多個script代碼段(用script標(biāo)簽分隔的js代碼或引入的js文件),它們的運行順序是:

步驟1. 讀入第一個代碼段(js執(zhí)行引擎并非一行一行地執(zhí)行程序,而是一段一段地分析執(zhí)行的)
步驟2. 做語法分析,有錯則報語法錯誤(比如括號不匹配等),并跳轉(zhuǎn)到步驟5
步驟3. 對var變量和function定義做“預(yù)解析”(永遠(yuǎn)不會報錯的,因為只解析正確的聲明)
步驟4. 執(zhí)行代碼段,有錯則報錯(比如變量未定義)
步驟5. 如果還有下一個代碼段,則讀入下一個代碼段,重復(fù)步驟2
步驟6. 結(jié)束

上面的分析已經(jīng)足夠清楚,步驟二、三和步驟四里的紅色字體可能是我們新手理解上的一個盲點,尤其是步驟三的“預(yù)解析”,如果不清楚什么叫預(yù)解析,總覺得不踏實。而步驟四的“有錯則報錯”也是經(jīng)常碰到的。舉例來說:

function funcTest() {
  alert(arg);
  var arg = 2;
}
funcTest();

上面這段代碼執(zhí)行時,彈出“undefined”,也就是說arg沒有定義,js的變量不是不用定義也可以嗎?

2、語法分析和“預(yù)解析”

(1)、從解釋型語言的編譯過程說起

眾所周知,javascript是解釋型語言,它不同于c#和java等編譯型語言。對于傳統(tǒng)編譯型語言來說,編譯步驟分為:詞法分析、語法分析、語義檢查、代碼優(yōu)化和字節(jié)生成;但對于解釋型語言來說,通過詞法分析和語法分析得到語法樹后,就可以開始解釋執(zhí)行了。

a、詞法分析

簡單地說,詞法分析是將字符流(char stream)轉(zhuǎn)換為記號流(token stream)。
但是這個轉(zhuǎn)換過程并不是可以用一句話就可以概括的那么簡單,我們可以試著用偽代碼理解一段簡單的程序:

代碼var result=x-y;的轉(zhuǎn)換大致可以表示如下:

NAME "result"
EQUALS
NAME "x"
MINUS
NAME "y"
SEMICOLON

b、語法分析

簡單地說,語法分析就是為了構(gòu)造合法的語法分析樹,而語法分析樹可以直觀地表示出推導(dǎo)的過程。

那么什么是語法分析樹?簡單地說,就是程序推導(dǎo)過程的描述。但是到底什么是語法樹,請參考專業(yè)文章,本篇略過。

c、其他

通過語法分析,構(gòu)造出語法分析樹后,接下來還可能需要進(jìn)一步的語義檢查。對于傳統(tǒng)強類型語言來說,語義檢查的主要部分是類型檢查,比如函數(shù)的實參和形參類型是否匹配等等。
結(jié)論:通過上面的分析可以看出,對于javascript引擎來說,肯定有詞法分析和語法分析,之后可能還有語義檢查、代碼優(yōu)化等步驟,等這些編譯步驟完成之后(任何語言都有編譯過程,只是解釋型語言沒有編譯成二進(jìn)制代碼),才會開始執(zhí)行代碼。

(2)、執(zhí)行過程

a、javascript的作用域機制

通過編譯,javascript代碼已經(jīng)翻譯成了語法樹,然后會立刻按照語法樹執(zhí)行。

進(jìn)一步的執(zhí)行過程,需要理解javascript的作用域機制:詞法作用域(lexcical scope)。通俗地講,就是javascript變量的作用域是在定義時決定而不是執(zhí)行時決定,也就是說詞法作用域取決于源碼,編譯器通過靜態(tài)分析就能確定,因此詞法作用域也叫做靜態(tài)作用域(static scope)。但需要注意,with和eval的語義無法僅通過靜態(tài)技術(shù)實現(xiàn),所以只能說javascript的作用域機制非常接近詞法作用域(lexical scope).

javascript引擎在執(zhí)行每個函數(shù)實例時,都會創(chuàng)建一個執(zhí)行環(huán)境(execution context)。執(zhí)行環(huán)境中包含一個調(diào)用對象(call object), 調(diào)用對象是一個scriptObject結(jié)構(gòu)(scriptObject是與函數(shù)相關(guān)的一套靜態(tài)系統(tǒng),與函數(shù)實例的生命周期保持一致),用來保存內(nèi)部變量表varDecls、內(nèi)嵌函數(shù)表funDecls、父級引用列表upvalue等語法分析結(jié)構(gòu)(注意varDecls和funDecls等信息是在語法分析階段就已經(jīng)得到,并保存在語法樹中。函數(shù)實例執(zhí)行時,會將這些信息從語法樹復(fù)制到scriptObject上)。

b、javascript作用域機制的實現(xiàn)方法

詞法作用域(lexical scope)是javascript的作用域機制,還需要理解它的實現(xiàn)方法,就是作用域鏈(scope chain)。作用域鏈?zhǔn)且粋€name lookup機制,首先在當(dāng)前執(zhí)行環(huán)境的scriptObject中尋找,沒找到,則順著upvalue到父scriptObject中尋找,一直lookup到全局調(diào)用對象(global object)。

現(xiàn)在回過頭來分析第二個問題:

var arg = 1;
function funcTest() {
  alert(arg);
  var arg = 2;
}
arg = 10;
funcTest();

在執(zhí)行funcTest函數(shù)時,也即進(jìn)入了funcTest對應(yīng)的作用域,js引擎在執(zhí)行時,當(dāng)遇到對變量名或者函數(shù)名的使用時,會首先在當(dāng)前作用域(也即funcTest對應(yīng)的作用域)查找變量或者函數(shù)(顯然,arg變量在funcTest對應(yīng)的作用域里被定義為var arg=2 所以alert方法的參數(shù)采用的是當(dāng)前作用域的arg,但是因為arg被定義在alert方法后,所以arg變量默認(rèn)值為undefined)。當(dāng)然,如果沒有找到就到上層作用域查找,依此類推(作用域范圍可以持續(xù)到j(luò)avascript運行環(huán)境的根:window對象)。

最后,讓你看的更清楚,上面的代碼其實可以等價于:

var arg = 1;
function funcTest() {
  var arg; //默認(rèn)值undefined
  alert(arg);
  arg = 2;
}
arg = 10;
funcTest();

c、閉包(closure)

當(dāng)一個函數(shù)實例執(zhí)行時,會創(chuàng)建或關(guān)聯(lián)到一個閉包。 (關(guān)于閉包,打算另寫一篇學(xué)習(xí)筆記)

scriptObject用來靜態(tài)保存與函數(shù)相關(guān)的變量表,閉包則在執(zhí)行期動態(tài)保存這些變量表及其運行值;

閉包的生命周期有可能比函數(shù)實例長。函數(shù)實例在活動引用為空后會自動銷毀;

閉包則要等要數(shù)據(jù)引用為空后,由javascript引擎回收(有些情況下不會自動回收,就導(dǎo)致了內(nèi)存泄漏)。

ps:關(guān)于“執(zhí)行過程”這一段比較拗口,名詞很多,不過別被它們嚇住,一旦理解了執(zhí)行環(huán)境(execution context)、調(diào)用對象(call object)、詞法作用域(lexical scope)、作用域鏈(scope chain)、閉包(closure)等這些概念,javascript的很多現(xiàn)象都能迎刃而解。

三、結(jié)語

通過第二段的分析,對照第一段筆者曾經(jīng)做出的判斷(你是不是也覺得筆者曾經(jīng)的分析和結(jié)論很幼稚(哪怕有時結(jié)果碰巧也對?。??!不是一般的膚淺啊,^_^),你會發(fā)現(xiàn)原來javascript還有這么多“玄機”,而要真正理解精通又談何容易?先“悟透”再說吧。

希望本文所述對大家JavaScript程序設(shè)計有所幫助。

相關(guān)文章

  • 使用dynatrace-ajax跟蹤JavaScript的性能

    使用dynatrace-ajax跟蹤JavaScript的性能

    DynaTrace 致力于分析后臺應(yīng)用性能的表現(xiàn)已經(jīng)好幾年了,最近,他們通過發(fā)布dynaTrace Ajax Edition進(jìn)入了前端性能分析領(lǐng)域. 它是一個運行在IE下的BHO免費工具. 雖然我喜歡Firefox和它下面的所有插件,但我知道基于IE的測試和調(diào)試也是很重要的。
    2010-04-04
  • 基于Bootstrap重置輸入框內(nèi)容按鈕插件

    基于Bootstrap重置輸入框內(nèi)容按鈕插件

    pureClearButton是一款基于Bootstrap的非常實用的用于清空和重置input輸入框內(nèi)容的jQuery按鈕插件,感興趣的小伙伴們可以參考一下
    2016-05-05
  • thinkjs之頁面跳轉(zhuǎn)同步異步操作

    thinkjs之頁面跳轉(zhuǎn)同步異步操作

    這篇文章主要介紹了thinkjs之頁面跳轉(zhuǎn)同步異步操作,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-02-02
  • js正則表達(dá)式replace替換變量方法

    js正則表達(dá)式replace替換變量方法

    這篇文章主要介紹了js正則表達(dá)式/replace替換變量方法 ,最近項目任務(wù)繁重,更新博客會較慢,不過有時間希望可以把自己的積累分享出來,需要的朋友可以參考下
    2016-05-05
  • Javascript中this關(guān)鍵字指向問題的測試與詳解

    Javascript中this關(guān)鍵字指向問題的測試與詳解

    this是Javascript中一個非常容易理解錯,進(jìn)而用錯的特性。所以下面這篇文章主要給大家介紹了關(guān)于Javascript中this關(guān)鍵字指向問題的相關(guān)資料,文中通過測試的題目考驗大家對this的熟悉程度,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • web基于瀏覽器的本地存儲方法應(yīng)用

    web基于瀏覽器的本地存儲方法應(yīng)用

    在客戶端存儲數(shù)據(jù)時,我們一般都用cookie(不敏感數(shù)據(jù)),但是在客戶端越來越富的今天,cookie可存儲的量(每個域最大4k)實在是小,已經(jīng)滿足不了我們的需求
    2012-11-11
  • js表單驗證實例講解

    js表單驗證實例講解

    這篇文章主要為大家詳細(xì)介紹了js表單驗證,JavaScript 可用來在數(shù)據(jù)被送往服務(wù)器前對HTML 表單中的這些輸入數(shù)據(jù)進(jìn)行驗證,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 比JSON.stringify快兩倍的fast-json-stringify性能對比分析

    比JSON.stringify快兩倍的fast-json-stringify性能對比分析

    這篇文章主要為大家介紹了比JSON.stringify快兩倍的fast-json-stringify性能對比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • javascript加減乘除的簡單實例

    javascript加減乘除的簡單實例

    下面小編就為大家?guī)硪黄猨avascript加減乘除的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • javascript 閉包

    javascript 閉包

    閉包是一個擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個函數(shù)),因而這些變量也是該表達(dá)式的一部分,本文將用通俗的語言帶您深入理解Javascript閉包的概念。
    2011-09-09

最新評論