国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript作用域和閉包之我見

SoapEye / 644人閱讀

摘要:查詢是在作用域鏈中,一級級的往上查找該變量的引用。作用域和作用域鏈作用域的概念,應該兩張圖幾句話就能解釋吧。這個建筑代表程序中的嵌套作用域鏈。一層嵌一層的作用域形成了作用域鏈,變量在作用域鏈中的函數(shù)內得到了自己的定義。

javascript作用域和閉包之我見

看了《你不知道的JavaScript(上卷)》的第一部分——作用域和閉包,感受頗深,遂寫一篇讀書筆記加深印象。路過的大牛歡迎指點,對這方面不懂的同學請繞道看書,以免誤人子弟... 看過這本書的可以一起交流交流。

編譯過程

理解js作用域首先要了解js的編譯過程(或者說解析過程)。

引擎

從頭到尾負責整個 JavaScript 程序的編譯及執(zhí)行過程。

編譯器

引擎的好朋友之一,負責語法分析及代碼生成等臟活累活(詳見前一節(jié)的內容)。

作用域

引擎的另一位好朋友,負責收集并維護由所有聲明的標識符(變量)組成的一系列查詢,并實施一套非常嚴格的規(guī)則,確定當前執(zhí)行的代碼對這些標識符的訪問權限。

都說node是基于chrome的V8引擎開發(fā) 的。那么V8是引擎,node是編譯器嗎?這個理解是錯誤的!我之前就是這么錯誤理解的,聽說node是用C++實現(xiàn)的,之前我一直以為V8是負責把javascript語言轉換成底層的C++,然后node很高級node負責編譯,做js的語法檢察,ES6的新特性全都是node的開發(fā)人員,一點點的開發(fā)支持起來的。然而現(xiàn)實是,V8包辦了所有js編譯的過程,而node只是一個環(huán)境。如nodejs.cn首頁所說Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環(huán)境。 ,是運行環(huán)境!node只是在V8的基礎上,做了終端命令行的支持、文件處理的支持、http服務的支持等等,相當于一個給V8提供了各種功能的殼子。

上面說的三點是包含關系,不是并行關系!引擎包含編譯器,對js進行編譯,然后根據(jù)作用域和語句執(zhí)行不同的代碼邏輯。

編譯器的查詢

我們將 var a = 2; 分解,看看引擎和它的朋友們是如何協(xié)同工作的。

編譯器首先會將這段程序分解成詞法單元,然后將詞法單元解析成一個樹結構。但是當編 譯器開始進行代碼生成時,它對這段程序的處理方式會和預期的有所不同。
可以合理地假設編譯器所產(chǎn)生的代碼能夠用下面的偽代碼進行概括:“為一個變量分配內 存,將其命名為 a,然后將值 2 保存進這個變量。”然而,這并不完全正確。
事實上編譯器會進行如下處理。

1.  遇到var a,編譯器會詢問作用域是否已經(jīng)有一個該名稱的變量存在于同一個作用域的 集合中。如果是,編譯器會忽略該聲明,繼續(xù)進行編譯;否則它會要求作用域在當前作 用域的集合中聲明一個新的變量,并命名為 a。
2.  接下來編譯器會為引擎生成運行時所需的代碼,這些代碼被用來處理a = 2這個賦值 操作。引擎運行時會首先詢問作用域,在當前的作用域集合中是否存在一個叫作 a 的 變量。如果是,引擎就會使用這個變量;如果否,引擎會繼續(xù)查找該變量。

如果引擎最終找到了 a 變量,就會將 2 賦值給它。否則引擎就會舉手示意并拋出一個異常!

在我們的例子中,引擎會為變量 a 進行 LHS 查詢。另外一個查找的類型叫作 RHS。

RHS 查詢與簡單地查找某個變量的值別無二致,而 LHS 查詢則是試圖 找到變量的容器本身,從而可以對其賦值。從這個角度說,RHS 并不是真正意義上的“賦 值操作的右側”,更準確地說是“非左側”。

你可以將RHS理解成retrieve his source value(取到它的源值),這意味著“得到某某的 值”。

怎么理解呢,我的理解是LHS 查詢是查詢變量的命名空間,然后進行賦值。RHS 查詢是在作用域鏈中,一級級的往上查找該變量的引用

所以:

function foo(a) { 
   var b=a;
   return a + b; 
}
var c=foo(2);

找到其中所有的LHS查詢。(這里有3處!)

找到其中所有的RHS查詢。(這里有4處!)

LHS:var c=的賦值、foo(2)傳參給foo(a)時的賦值、var b=的賦值
RHS:foo(2)函數(shù)調用時查找foo()方法、var b=a中a查找自己的值、a+b中a和b兩個參數(shù)查找自己的值。

作用域和作用域鏈

作用域的概念,應該兩張圖幾句話就能解釋吧。

這個建筑代表程序中的嵌套作用域鏈。第一層樓代表當前的執(zhí)行作用域,也就是你所處的 位置。建筑的頂層代表全局作用域。

LHS 和 RHS 引用都會在當前樓層進行查找,如果沒有找到,就會坐電梯前往上一層樓, 如果還是沒有找到就繼續(xù)向上,以此類推。一旦抵達頂層(全局作用域),可能找到了你 所需的變量,也可能沒找到,但無論如何查找過程都將停止。

① 包含著整個全局作用域,其中只有一個標識符:foo。
② 包含著 foo 所創(chuàng)建的作用域,其中有三個標識符:a、bar 和 b。
③ 包含著 bar 所創(chuàng)建的作用域,其中只有一個標識符:c。
作用域氣泡由其對應的作用域塊代碼寫在哪里決定,它們是逐級包含的。

我覺得,說一個變量屬于哪個作用域,可以顧名思義用該變量生效的區(qū)域來解釋,所以上圖中的b變量,可以說屬于bar()的函數(shù)作用域內,也可以說是foo()的函數(shù)作用域內,也可以說是全局作用域內。
一層嵌一層的作用域形成了作用域鏈,變量b在作用域鏈中的foo()函數(shù)內得到了自己的定義。

改變作用域

eval(..) 和 with 會在運行時修改或創(chuàng)建新的作用域,以此來欺騙其他在書寫時定義的詞法作用域。

JavaScript 引擎會在編譯階段進行數(shù)項的性能優(yōu)化。其中有些優(yōu)化依賴于能夠根據(jù)代碼的 詞法進行靜態(tài)分析,并預先確定所有變量和函數(shù)的定義位置,才能在執(zhí)行過程中快速找到 標識符。
但如果引擎在代碼中發(fā)現(xiàn)了 eval(..) 或 with,它只能簡單地假設關于標識符位置的判斷 都是無效的,因為無法在詞法分析階段明確知道 eval(..) 會接收到什么代碼,這些代碼會 如何對作用域進行修改,也無法知道傳遞給 with 用來創(chuàng)建新詞法作用域的對象的內容到底 是什么。

這兩個機制的副作用是引擎無法在編譯時對作用域查找進行優(yōu)化,因為引擎只能謹慎地認 為這樣的優(yōu)化是無效的。使用這其中任何一個機制都將導致代碼運行變慢。不要使用它們。

call()bind()之類的是改變作用域嗎?他們只是改變了this的指向并不算改變作用域,是可以在編譯階段進行靜態(tài)分析,所以不會導致上面說的無法優(yōu)化的情況。

形成作用域

我們知道函數(shù)可以形成作用域,還有哪些方式形成作用域呢?

with

可以指定變量的作用域(選擇一個對象),在它的塊作用域內,變量就相當于這個對象的屬性。

var obj={
    a: 1,
    b: 2,
    c:3
};
// 單調乏味的重復 "obj" 
obj.a = 2;
obj.b = 3;
obj.c = 4;
// 簡單的快捷方式 
with (obj) {
    a=3; 
    b=4; 
    c=5;
}

不被推薦,因為它會影響性能,且不易閱讀(代碼塊內的代碼特別多的情況,根本不知道這個是普通的變量還是某個對象的屬性,還是某個對象的屬性的屬性的屬性)。

try/catch
try {
    undefined(); // 執(zhí)行一個非法操作來強制制造一個異常
}
catch (err) {
    console.log( err ); // 能夠正常執(zhí)行! 
}
console.log( err ); // ReferenceError: err not found

做錯誤狀態(tài)傳參的err變量是當前塊的局部變量。
但是如果在catch(err){…}內部var其它變量,并沒有效果,見下面代碼。

try {
    var abc="測試try塊中的變量"
}
catch (err) {
    var b=2;    // 沒有錯誤,不會被執(zhí)行到的。
}
console.log( abc ); // 測試try塊中的變量
try {
    throw "55";    // 制造一個異常
}
catch (err) {
    var abc="測試catch塊中的變量";
}
console.log(abc);        // 測試catch塊中的變量

這是只屬于err參數(shù)用的偽塊作用域。

let、const

ES6新特性,大神器。在{}中形成塊作用域,且不會遇到提升 的問題出現(xiàn)。
為變量顯式聲明塊作用域,有助于回收內存垃圾

function process(data) { 
    // 在這里做點有趣的事情
}

// 在這個塊中定義的內容可以銷毀了! (這里指的是下面let定義的`someReallyBigData`)
{
    let someReallyBigData = { .. }; 
    process( someReallyBigData );
}

var btn = document.getElementById( "my_button" );

btn.addEventListener( "click", function click(evt){
         console.log("button clicked");
}, /*capturingPhase=*/false );

let有一個很有意思的地方,就是在for循環(huán)中。

for (let i=0; i<10; i++) {
    console.log( i );
}
console.log( i ); // ReferenceError

for 循環(huán)頭部的 let 不僅將 i 綁定到了 for 循環(huán)的塊中,事實上它將其重新綁定到了循環(huán) 的每一個迭代中,確保使用上一個循環(huán)迭代結束時的值重新進行賦值。
下面通過另一種方式來說明每次迭代時進行重新綁定的行為:

{
    let j;
    for (j=0; j<10; j++) {
        let i = j; // 每個迭代重新綁定!
        console.log( i );
    }
}
提升

編譯器在解析作用域時,會對作用域中var聲明的變量、函數(shù)進行提升

a=2;
var a; 
console.log( a );    // 2

相當于

var a;
a=2;
console.log( a );    // 2
console.log( a );     // undefined
var a=2;

相當于

var a; 
console.log( a );     // undefined
a=2;

函數(shù)聲明和變量聲明都會被提升。但是一個值得注意的細節(jié)(這個細節(jié)可以出現(xiàn)在有多個“重復”聲明的代碼中)是函數(shù)會首先被提升,然后才是變量。

foo(); // 1
var foo;
function foo() { 
    console.log( 1 );
}
foo = function() { 
    console.log( 2 );
};

相當于

function foo() { 
    console.log( 1 );
}
foo(); // 1
foo = function() { 
    console.log( 2 );
};
閉包

當函數(shù)可以記住并訪問所在的詞法作用域,即使函數(shù)是在當前詞法作用域之外執(zhí)行,這時就產(chǎn)生了閉包。

function foo() {
    var a=2;
    function baz() { 
        console.log( a ); // 2
    }
    bar( baz ); 
}
function bar(fn) {
    fn(); // 媽媽快看呀,這就是閉包!
}

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81973.html

相關文章

  • Spring框架我見(四)——Spring MVC

    摘要:是結構在框架中的一種表現(xiàn)形式。這句話聽起來有點繞,我們可以看一下下面這張圖,大家可以吧容器中的理解為全局變量,吧容器中的理解為局部變量。在方法體中可以訪問局部變量和全局變量,但是在方法外,就只能訪問全局變量,是不能訪問局部變量的。 聊完了Spring,我們來看看Spring在web方面的應用Spring MVC。 MVC 首先我們來看什么是mvc? 大家知道在jsp里面也是可以寫jav...

    shiina 評論0 收藏0
  • 秒殺系統(tǒng)架構如何設計我見

    摘要:即使秒殺系統(tǒng)崩潰了,也不會對網(wǎng)站造成影響。動態(tài)生成隨機下單頁面的為了避免用戶直接訪問下單需要將動態(tài)化,用隨機數(shù)作為參數(shù),只能秒殺開始的時候才生成。架構設計如何控制秒殺商品頁面搶購按鈕的可用禁用。該文件不被緩存的做法隨機數(shù)。 秒殺背景 電商中為了吸引顧客、聚集人氣,經(jīng)常會策劃一些秒殺活動。活動中售賣的商品,要么價格遠低于市場價格,要么比較稀缺(如一些新發(fā)布的商品)。這些商品電商一般都會限...

    zhunjiee 評論0 收藏0
  • 秒殺系統(tǒng)架構如何設計我見

    摘要:即使秒殺系統(tǒng)崩潰了,也不會對網(wǎng)站造成影響。動態(tài)生成隨機下單頁面的為了避免用戶直接訪問下單需要將動態(tài)化,用隨機數(shù)作為參數(shù),只能秒殺開始的時候才生成。架構設計如何控制秒殺商品頁面搶購按鈕的可用禁用。該文件不被緩存的做法隨機數(shù)。 秒殺背景 電商中為了吸引顧客、聚集人氣,經(jīng)常會策劃一些秒殺活動。活動中售賣的商品,要么價格遠低于市場價格,要么比較稀缺(如一些新發(fā)布的商品)。這些商品電商一般都會限...

    zhkai 評論0 收藏0
  • 秒殺系統(tǒng)架構如何設計我見

    摘要:即使秒殺系統(tǒng)崩潰了,也不會對網(wǎng)站造成影響。動態(tài)生成隨機下單頁面的為了避免用戶直接訪問下單需要將動態(tài)化,用隨機數(shù)作為參數(shù),只能秒殺開始的時候才生成。架構設計如何控制秒殺商品頁面搶購按鈕的可用禁用。該文件不被緩存的做法隨機數(shù)。 秒殺背景 電商中為了吸引顧客、聚集人氣,經(jīng)常會策劃一些秒殺活動。活動中售賣的商品,要么價格遠低于市場價格,要么比較稀缺(如一些新發(fā)布的商品)。這些商品電商一般都會限...

    HmyBmny 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<