成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

談?wù)刯avascript語法里一些難點問題(二)

Enlightenment / 2291人閱讀

摘要:講作用域鏈?zhǔn)紫纫獜淖饔糜蛑v起,下面是百度百科里對作用域的定義作用域在許多程序設(shè)計語言中非常重要。原文出處談?wù)務(wù)Z法里一些難點問題二

3) 作用域鏈相關(guān)的問題

作用域鏈?zhǔn)莏avascript語言里非常紅的概念,很多學(xué)習(xí)和使用javascript語言的程序員都知道作用域鏈?zhǔn)抢斫鈐avascript里很重要的一些概念的關(guān)鍵,這些概念包括this指針,閉包等等,它非常紅的另一個重要原因就是作用域鏈理解起來太難,就算有人真的感覺理解了它,但是碰到很多實際問題時候任然會是丈二和尚摸不到頭腦,例如上篇引子里講到的例子,本篇要講的主題就是作用域鏈,再無別的內(nèi)容,希望看完本文的朋友能有所收獲。

講作用域鏈?zhǔn)紫纫獜淖饔糜蛑v起,下面是百度百科里對作用域的定義:

作用域在許多程序設(shè)計語言中非常重要。

通常來說,一段程序代碼中所用到的名字并不總是有效/可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。

作用域的使用提高了程序邏輯的局部性,增強程序的可靠性,減少名字沖突。

在我最擅長的服務(wù)端語言java里也有作用域的概念,java里作用域是以{}作為邊界,不過在純種的面向?qū)ο笳Z言里我們沒必要把作用域研究的那么深,也沒必要思考復(fù)雜的作用域嵌套問題,因為這些語言關(guān)于作用域的深度運用并不會給我們編寫的代碼帶來多大好處。但是在javascript里卻大不相同,如果我們不能很好的理解javascript的作用域我們就沒辦法使用javascript編寫出復(fù)雜的或者規(guī)模宏大的程序。

由百度百科里的定義,我們知道作用域的作用是保證變量的名字不發(fā)生沖突,用現(xiàn)實的場景來理解有個人叫做張三,張三雖然只是一個名字,但是認(rèn)識張三的人根據(jù)名字就能唯一確認(rèn)這個人到底是誰,但是這個世界上叫做張三的人可不止一個,特別是兩個叫張三的人有交集的時候我們就要有個辦法明確指定這個張三絕不是另外一個張三,這時我們可能會根據(jù)兩大張三年齡的差異來區(qū)分:例如一個張三叫大張三,相對的另外一個張三叫小張三了。編程語言里的作用域其實就是為了做類似的標(biāo)記,作用域會設(shè)定一個范圍,在這個范圍里我們是不會弄錯變量的真實含義。

前面我講到在java里通過{}來設(shè)置作用域,在{}里面的變量會得到保護,這種保護就是不讓{}里的變量被外部變量混淆和污染。那么{}的方式適合于javascript嗎?我們看看下面的例子:

var s1 = "sharpxiajun";

function ftn(){

    var s2 = "xtq";

    console.log(this);// 運行結(jié)果: window

    console.log("s1:" + this.s1 + ";s2:" + this.s2);//運行結(jié)果:s1:sharpxiajun;s2:undefined

    console.log("s1:" + this.s1 + ";s2:" + s2);// 運行結(jié)果:s1:sharpxiajun;s2:xtq

}

ftn();

在javascript世界里有一個大的作用域環(huán)境,這個環(huán)境就是window,window環(huán)境不需要我們自己使用什么方式構(gòu)建,頁面加載時候頁面會自動構(gòu)造的,上面代碼里有一個大括號,這個大括號是對函數(shù)的定義,運行之,我們發(fā)現(xiàn)函數(shù)作用域內(nèi)部定義的s2變量是不能被window對象訪問的,因此s2變量是被{}保護起來了,它的生命周期和這個函數(shù)的生命周期有關(guān)。

由這個例子是不是說明在javascript里,變量也是被{}保護起來了,在javascript語言里還有非函數(shù)的{},我們再看看下面的例子:

if (true){

    var a = "aaaa";

}

console.log(a);// 運行結(jié)果:aaaa

我們發(fā)現(xiàn)javascript里{}有時是起不到定義作用域的功能。這也說明javascript里的作用域定義是和其他語言例如java不同的。

在javascript里作用域有一個專門的定義execution context,有的書里把這個名字翻譯成執(zhí)行上下文,有的書籍里把它翻譯成執(zhí)行環(huán)境,我更傾向于后者執(zhí)行環(huán)境,下文我提到的執(zhí)行環(huán)境就是execution context。這個命名非常形象,這個形象體現(xiàn)在execution這個單詞,execution含義就是執(zhí)行,我們來想想javascript里那些情況是執(zhí)行:

情況一:當(dāng)頁面加載時候在script標(biāo)簽下的javascript代碼會按順序執(zhí)行,而這些能被執(zhí)行的代碼都是屬于window的變量或函數(shù);

情況二:當(dāng)函數(shù)的名字后面加上小括號(),例如ftn(),這也是在執(zhí)行,不過它執(zhí)行的是函數(shù)。

如此說來,javascript里的執(zhí)行環(huán)境有兩類一類是全局執(zhí)行環(huán)境,即window代表的全局環(huán)境,一類是函數(shù)代表的函數(shù)執(zhí)行環(huán)境,這也就是我們常說的局部作用域。

執(zhí)行環(huán)境在javascript語言里并非是一個抽象的概念,而是有具體的實現(xiàn),這個實現(xiàn)其實是個對象,這個對象也有個名字叫做variable object,這個變量有的書里翻譯為變量對象,這是直譯,有的書里把它稱為上下文變量,這里我還是傾向于后者上下文變量,下文里提到的上下文變量就是指代variable object。上下文變量存儲的是上下文變量所處執(zhí)行環(huán)境里定義的所有的變量和函數(shù)。

全局執(zhí)行環(huán)境的上下文變量是可以訪問到的,它就是window對象,所以我們說window能代表全局作用域是有道理的,但是局部作用域即函數(shù)的執(zhí)行環(huán)境里的上下文變量是代碼不能訪問到的,不過javascript引擎在處理數(shù)據(jù)時候會使用到它。

在javascript語言里還有一個概念,它的名字叫做execution context stack,翻譯成中文就是執(zhí)行環(huán)境棧,每個要被執(zhí)行的函數(shù)都會先把函數(shù)的執(zhí)行環(huán)境壓入到執(zhí)行環(huán)境棧里,函數(shù)執(zhí)行完畢后,這個函數(shù)的執(zhí)行環(huán)境就會被執(zhí)行環(huán)境棧彈出,例如上面的例子:函數(shù)執(zhí)行時候函數(shù)的執(zhí)行環(huán)境會被壓入到執(zhí)行環(huán)境棧里,函數(shù)執(zhí)行完畢,執(zhí)行環(huán)境棧會把這個環(huán)境彈出,執(zhí)行環(huán)境棧的控制權(quán)就會交由全局環(huán)境,如果函數(shù)后面還有代碼,那么代碼就是接著執(zhí)行。如果函數(shù)里嵌套了函數(shù),那么嵌套函數(shù)執(zhí)行完畢后,執(zhí)行環(huán)境棧的控制權(quán)就交由了外部函數(shù),然后依次類推,最后就是全局執(zhí)行環(huán)境了。

講到這里我們大名鼎鼎的作用域鏈要登場了,函數(shù)的執(zhí)行環(huán)境被壓入到執(zhí)行環(huán)境棧里后,函數(shù)就要執(zhí)行了,函數(shù)執(zhí)行的第一步不是執(zhí)行函數(shù)里的第一行代碼而是在上下文變量里構(gòu)造一個作用域鏈,作用域鏈的英文名字叫做scope chain,作用域鏈的作用是保證執(zhí)行環(huán)境里有權(quán)訪問的變量和函數(shù)是有序的,這個概念里有兩個關(guān)鍵意思:有權(quán)訪問和有序,我們看看下面的代碼:

 var b1 = "b1";

    function ftn1(){

        var b2 = "b2";

        var b1 = "bbb";

        function ftn2(){

            var b3 = "b3";

            b2 = b1;

            b1 = b3;

            console.log("b1:" + b1 + ";b2:" + b2 + ";b3:" + b3);// 運行結(jié)果:b1:b3;b2:bbb;b3:b3

        }

        ftn2();

    }

    ftn1();

console.log(b1);// 運行結(jié)果:b1

有這個例子我們發(fā)現(xiàn),ftn2函數(shù)可以訪問變量b1,b2,這個體現(xiàn)了有權(quán)訪問的概念,當(dāng)ftn1作用域里改變了b1的值并且把b1變量重新定義為ftn1的局部變量,那么ftn2訪問到的b1就是ftn1的,ftn2訪問到b1后就不會在全局作用域里查找b1了,這個體現(xiàn)了有序性。

下面我要總結(jié)下上面講述的知識:

本篇的小標(biāo)題是:作用域鏈的相關(guān)問題,這個標(biāo)題定義的含義是指作用域鏈?zhǔn)谴竺Χα?,但是作用域鏈在廣大程序員的理解里其實包含的意義已經(jīng)超越了作用域鏈在javascript語言本身的定義。廣大程序員對作用域鏈的理解有兩塊一塊是作用域,而作用域在javascript語言里指的是執(zhí)行環(huán)境execution context,執(zhí)行環(huán)境在javascript引擎里是通過上下文變量體現(xiàn)的variable object,javascript引擎里還有一個概念就是執(zhí)行環(huán)境棧execution context stack,當(dāng)某一個函數(shù)的執(zhí)行環(huán)境壓入到了執(zhí)行環(huán)境棧里,這個時候就會在上下文變量里構(gòu)造一個對象,這個對象就是作用域鏈scope chain,而這個作用域鏈就是廣大程序員理解的第二塊知識,作用域鏈的作用是保證執(zhí)行環(huán)境里有權(quán)訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對象即被終止,作用域鏈向下訪問變量是不被允許的。

很多人常常認(rèn)為作用域鏈?zhǔn)抢斫?b>this指針的關(guān)鍵,這個理解是不正確的的,this指針構(gòu)造是和作用域鏈同時發(fā)生的,也就是說在上文變量構(gòu)建作用域鏈的同時還會構(gòu)造一個this對象,this對象也是屬于上下文變量,而this變量的值就是當(dāng)前執(zhí)行環(huán)境外部的上下文變量的一份拷貝,這個拷貝里是沒有作用域鏈變量的,例如代碼:

var b1 = "b1";

function ftn1(){

    console.log(this);// 運行結(jié)果: window

    var b2 = "b2";

    var b1 = "bbb";

    function ftn2(){

        console.log(this);// 運行結(jié)果: window

        var b3 = "b3";

        b2 = b1;

        b1 = b3;

        console.log("b1:" + b1 + ";b2:" + b2 + ";b3:" + b3);// 運行結(jié)果:b1:b3;b2:bbb;b3:b3

    }

    ftn2();

}

ftn1();

我們看到函數(shù)ftn1和ftn2里的this指針都是指向window,這是為什么了?因為在javascript我們定義函數(shù)方式是通過function xxx(){}形式,那么這個函數(shù)不管定義在哪里,它都屬于全局對象window,所以他們的執(zhí)行環(huán)境的外部的執(zhí)行上下文都是指向window。

但是我們都知道現(xiàn)實代碼很多this指針都不是指向window,例如下面的代碼:

var obj = {

name:"sharpxiajun",

ftn:function(){

    console.log(this);// 運行結(jié)果: Object { name="sharpxiajun", ftn=function()}

    console.log(this.name);//運行結(jié)果: sharpxiajun

}

}

obj.ftn();// :

運行之,我們發(fā)現(xiàn)這里this指針指向了Object,這就怪了我前文不是說javascript里作用域只有兩種類型:一個是全局的一個是函數(shù),為什么這里Object也是可以制造出作用域了,那么我的理論是不是有問題?。磕俏覀兛纯聪旅娴拇a:

var obj1 = new Object();

obj1.name = "xtq";

obj1.ftn = function(){

    console.log(this);// 運行結(jié)果: Object { name="xtq", ftn=function()}

    console.log(this.name);//運行結(jié)果: xtq

}

obj1.ftn();

這兩種寫法是等價的,第一種對象的定義方法叫做字面量定義,而第二種寫法則是標(biāo)準(zhǔn)寫法,Object對象的本質(zhì)也是個function,所以當(dāng)我們調(diào)用對象里的函數(shù)時候,函數(shù)的外部執(zhí)行環(huán)境就是obj1本身,即外部執(zhí)行環(huán)境上下文變量代表的就是obj1,那么this指針也是指向了obj1。

原文出處:談?wù)刯avascript語法里一些難點問題(二)

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85557.html

相關(guān)文章

  • 談?wù)?/em>javascript語法一些難點問題(一)

    摘要:引子前不久我建立的技術(shù)群里一位問了一個這樣的問題,她貼出的代碼如下所示執(zhí)行結(jié)果如下所示第一個第二個這是一個令人詫異的結(jié)果,為什么第一個彈出框顯示的是,而不是呢這種疑惑的原理我描述如下一個頁面里直接定義在標(biāo)簽下的變量是全局變量即屬于對象的變量 1) 引子 前不久我建立的技術(shù)群里一位MM問了一個這樣的問題,她貼出的代碼如下所示: var a = 1; function hehe...

    huaixiaoz 評論0 收藏0
  • 你需要知道面試中的10個JavaScript概念

    摘要:自我學(xué)習(xí)目前有成千上萬的年輕人在學(xué)習(xí)和開發(fā),希望獲得一份工作。知道的綁定規(guī)則。知道和原型屬性是什么以及它們的作用。高階函數(shù)了解函數(shù)是中的一級對象,這意味著什么知道從另一個函數(shù)返回函數(shù)是完全合法的。了解閉包和高階函數(shù)允許我們使用的情況。 翻譯原文出處:10 JavaScript concepts you need to know for interviews 之前不是鬧得沸沸揚揚的大漠窮...

    YacaToy 評論0 收藏0
  • 前端_JavaScript

    摘要:為此決定自研一個富文本編輯器。例如當(dāng)要轉(zhuǎn)化的對象有環(huán)存在時子節(jié)點屬性賦值了父節(jié)點的引用,為了關(guān)于函數(shù)式編程的思考作者李英杰,美團金融前端團隊成員。只有正確使用作用域,才能使用優(yōu)秀的設(shè)計模式,幫助你規(guī)避副作用。 JavaScript 專題之惰性函數(shù) JavaScript 專題系列第十五篇,講解惰性函數(shù) 需求 我們現(xiàn)在需要寫一個 foo 函數(shù),這個函數(shù)返回首次調(diào)用時的 Date 對象,注意...

    Benedict Evans 評論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識之 HTTP 協(xié)議 詳細介紹 HTT...

    rottengeek 評論0 收藏0

發(fā)表評論

0條評論

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