溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

好程序員web前端帶你了解JS的作用域鏈

發(fā)布時(shí)間:2020-08-09 09:28:08 來(lái)源:ITPUB博客 閱讀:139 作者:好程序員IT 欄目:web開(kāi)發(fā)

好程序員 web前端帶 你了解 JS的作用域鏈, 我們都知道 js 是一個(gè)基于對(duì)象的語(yǔ)言,系統(tǒng)內(nèi)置各種對(duì)象。

 

window 作為一個(gè)天然存在的全局對(duì)象,它承擔(dān)了所有全局資源的存儲(chǔ)。

 

我們使用的任何全局變量,都是 window 下的。也就是說(shuō),在 js 中,實(shí)際上沒(méi)有任何對(duì)象、方法是可以獨(dú)立的,它們必須依賴于某個(gè)對(duì)象才可以被訪問(wèn)或執(zhí)行。

 

就像 alert() ,它的完整寫法是 window.alert()

parseInt(),  完整寫法是 window.parseInt()

 

所有放在 window 對(duì)象下的資源,訪問(wèn)時(shí)可以默認(rèn)省略 window

 

但有一種情況非常特殊,例如函數(shù)中的局部變量:

function  Person(){

        var  name =  “abc” ;

}

當(dāng)我們?cè)噲D訪問(wèn)這個(gè) name 屬性時(shí)

console.log(newPerson().name); 

結(jié)果是 undefined

我們只能在函數(shù)內(nèi)部訪問(wèn):

function  Person(){

        var  name =  “abc”;

        console .log(name);

}

這種屬性,在構(gòu)造函數(shù)中,也被稱為私有屬性,我們必須提供一種對(duì)外公開(kāi)的方法才可以被外界訪問(wèn)。例如:

function  Person(){

        var  name =  “abc” ;

        this .getName =  function (){

        return name;

}

this .setName=  function (_name){

       name = _name;

}

}

這是一個(gè)典型的作用域問(wèn)題 似乎我們每個(gè)人都知道。

 

但這似乎也違反了我們的一個(gè)常識(shí):那就是在 js 中,所有資源都必須依賴對(duì)象才能存在,不可獨(dú)立使用。比如說(shuō):

function  aaa(){

        function  bbb(){  }

       bbb();

}

這段代碼看上去并沒(méi)有錯(cuò),但是請(qǐng)問(wèn) bbb 這個(gè)函數(shù)為什么可以獨(dú)立存在呢?如果我們把它換成這樣:

function  aaa(){

        function  bbb(){  }

        window .bbb();

}

結(jié)果是運(yùn)行錯(cuò)誤!

 

那如果換成這樣呢?

function  aaa(){

        function  bbb(){  }

        this .bbb();

}

結(jié)果還是運(yùn)行錯(cuò)誤!

 

那么我們不禁要發(fā)問(wèn)了, bbb 這個(gè)函數(shù)到底是屬于哪個(gè)對(duì)象的?

 

當(dāng)我們?cè)谡{(diào)用一個(gè)函數(shù)的時(shí)候,瀏覽器會(huì)為這個(gè)函數(shù)的執(zhí)行開(kāi)辟一塊內(nèi)存區(qū)域用來(lái)存儲(chǔ)這個(gè)方法在執(zhí)行的臨時(shí)數(shù)據(jù)。而對(duì)象作為 js 的基本存儲(chǔ)單位,因此,臨時(shí)數(shù)據(jù)實(shí)際上都被保存到了一個(gè)對(duì)象當(dāng)中,這個(gè)對(duì)象,就是我們平時(shí)所說(shuō)的 執(zhí)行上下文環(huán)境

 

當(dāng)我們調(diào)用 aaa 函數(shù)時(shí),例如 window.aaa()

瀏覽器會(huì)為這一次函數(shù)的執(zhí)行,創(chuàng)建一個(gè)執(zhí)行上下文環(huán)境對(duì)象,我們暫時(shí)給它起個(gè)名字,叫做 contextAAA 吧,當(dāng)然它是臨時(shí)的,因?yàn)楹瘮?shù)執(zhí)行完它也就消失了。

 

那我們的代碼實(shí)際上會(huì)變成這樣:

function  aaa(){

        function  bbb(){   }

        contextAAA .bbb();

}

盡管 contextAAA 對(duì)象是看不見(jiàn)的,但它確實(shí)存在。

 

而當(dāng)我們執(zhí)行 bbb 函數(shù)時(shí),瀏覽器會(huì)再次為這一次函數(shù)調(diào)用創(chuàng)建一個(gè)臨時(shí)的執(zhí)行上下文環(huán)境,我們暫且叫它 contextBBB

那么 contextAAA  contextBBB以及window 之間會(huì)形成鏈條關(guān)系,

舉個(gè)例子來(lái)說(shuō)明吧

var  num = 888;

function  aaa(){

        var  num = 100;

        function  bbb(){

        var  num= 200;

        console .log(num);

}

bbb();

}

aaa();

那么 contextAAA  如下:

contextAAA = {

       num  100,

       bbb :  function (){ … },

       parentContext:  window // 父級(jí)上下文對(duì)象

}

那么 contextBBB 如下:

contextBBB = {

       num : 200,

       parentContext: contextAAA // 父級(jí)上下文對(duì)象

}

因此我們發(fā)現(xiàn),在父級(jí)上下文對(duì)象中,我們沒(méi)有辦法訪問(wèn)到子級(jí)上下對(duì)象,這是一個(gè)單向鏈表,這就是全局不能訪問(wèn)局部的原因。

 

bbb 函數(shù)中打印出的 num 應(yīng)該是多少呢?這取決在上下文對(duì)象中的查找順序,順序大概是這樣的:

首先在當(dāng)前上下文對(duì)象 contextBBB 中,找一下有沒(méi)有 num 變量,找到就直接打印。以我們目前的代碼看,結(jié)果應(yīng)該是 200

我們把代碼改造一下:

var  num= 888;

function  aaa(){

        var  num = 100;

        function  bbb(){

        console .log(num);

}

bbb();

}

aaa();

由于這次在 contextBBB 對(duì)象中找不到 num 變量了,因此它會(huì)從父級(jí)上下文對(duì)象中查找,也就是 contextAAA 里面的 num ,因此打印的結(jié)果是 100;

我們?cè)侔汛a改造一下

var  num= 888;

function  aaa(){

        function  bbb(){

        console .log(num);

}

bbb();

}

aaa();

由于這次連 contextAAA 對(duì)象里也找不到了,會(huì)再次向它的父級(jí)上下文對(duì)象,也就是 window 查找,因此打印結(jié)果是 888

 

contextAAA contextBBB 的父子關(guān)系,在你寫代碼的一刻就決定了,這就是作用域。

function  aaa(){

        var  num = 10;

        function  bbb(){   console .log(num);  }

}

而代碼執(zhí)行時(shí),產(chǎn)生的上下文對(duì)象,是鏈表的關(guān)系。這就是我們所說(shuō)的作用域鏈,它的原理跟原型鏈?zhǔn)且粯拥摹?

好程序員web前端帶你了解JS的作用域鏈

理解了這一點(diǎn),也能弄明白閉包的原理。

function  aaa(){

       var  num = 10;

        return   function bbb(){   console .log(num);  }

}

aaa( )( )

盡管 bbb函數(shù)通過(guò)return在全局范圍被執(zhí)行了,但作用域的鏈表關(guān)系并沒(méi)有發(fā)生改變,因此,bbb函數(shù)依然可以訪問(wèn)num這個(gè)局部變量。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI