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

js作用域及作用域鏈工作引擎

 更新時(shí)間:2022年07月06日 11:32:49   作者:fieemiracle  
這篇文章主要為大家介紹了js作用域及作用域鏈工作引擎,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

我們需要先知道的是引擎,引擎的工作簡(jiǎn)單粗暴,就是負(fù)責(zé)javascript從頭到尾代碼的執(zhí)行。引擎的一個(gè)好朋友是編譯器,主要負(fù)責(zé)代碼的分析和編譯等;引擎的另一個(gè)好朋友就是今天的主角--作用域。那么作用域用來(lái)干什么呢?作用域鏈跟作用域又有什么關(guān)系呢?

一、作用域(scope)

作用域的定義:作用域是在運(yùn)行時(shí)代碼中的某些特定部分中變量,函數(shù)和對(duì)象的可訪問(wèn)性。

1.作用域的分類(lèi)

  • 全局作用域
var name="global";
function foo(){
    console.log(name);
}
foo();//global

這里函數(shù)foo()內(nèi)部并沒(méi)有聲明name變量,但是依然打印了name的值,說(shuō)明函數(shù)內(nèi)部可以訪問(wèn)到全局作用域,讀取name變量。再來(lái)一個(gè)例子:

hobby='music';
function foo(){
    hobby='book';
    console.log(hobby);
}
foo();//book

這里全局作用域和函數(shù)foo()內(nèi)部都沒(méi)有聲明hobby這個(gè)變量,為什么不會(huì)報(bào)錯(cuò)呢?這是因?yàn)閔obby='music';寫(xiě)在了全局作用域,就算沒(méi)有var,let,const的聲明,也會(huì)被掛在window對(duì)象上,所以函數(shù)foo()不僅可以讀取,還可以修改值。也就是說(shuō)hobby='music';等價(jià)于window.hobby='music';。

2.函數(shù)體作用域

函數(shù)體的作用域是通過(guò)隱藏內(nèi)部實(shí)現(xiàn)的。換句話說(shuō),就是我們常說(shuō)的,內(nèi)層作用域可以訪問(wèn)外層作用域,但是外層作用域不能訪問(wèn)內(nèi)層。原因,說(shuō)到作用域鏈的時(shí)候就迎刃而解了。

function foo(){
    var age=19;
    console.log(age);
}
console.log(age);//ReferenceError:age is not defined

很明顯,全局作用域下并沒(méi)有age變量,但是函數(shù)foo()內(nèi)部有,但是外部訪問(wèn)不到,自然而然就會(huì)報(bào)錯(cuò)了,而函數(shù)foo()沒(méi)有調(diào)用,也就不會(huì)執(zhí)行。

3.塊級(jí)作用域

塊級(jí)作用域更是見(jiàn)怪不怪,像我們接觸的let作用域,代碼塊{},for循環(huán)用let時(shí)的作用域,if,while,switch等等。然而,更深刻理解塊級(jí)作用域的前提是,我們需要先認(rèn)識(shí)認(rèn)識(shí)這幾個(gè)名詞:

--標(biāo)識(shí)符:能在作用域生效的變量。函數(shù)的參數(shù),變量,函數(shù)名。需要格外注意的是:函數(shù)體內(nèi)部的標(biāo)識(shí)符外部訪問(wèn)不到。

--函數(shù)聲明:function 函數(shù)名(){}

--函數(shù)表達(dá)式: var 函數(shù)名=function(){}

--自執(zhí)行函數(shù): (function 函數(shù)名(){})();自執(zhí)行函數(shù)前面的語(yǔ)句必須有分號(hào),通常用于隱藏作用域。

接下來(lái)我們就用一個(gè)例子,一口氣展示完吧

function foo(sex){
    console.log(sex);
}
var f=function(){
    console.log('hello');
}
var height=180;
(
    function fn(){
        console.log(height);
    }
)();
foo('female');
//依次打?。?
//180
//female
//hello

分析一下:標(biāo)識(shí)符:foo,sex,height,fn;函數(shù)聲明:function foo(sex){};函數(shù)表達(dá)式:var f=function(){};自執(zhí)行函數(shù):(function fn(){})();需要注意,自執(zhí)行函數(shù)fn()前面的var height=180;語(yǔ)句,分號(hào)不能拋棄。否則,你可以試一下。

二、預(yù)編譯

說(shuō)好只是作用域和作用域鏈的,但是考慮到理解作用域鏈的必要性,這里還是先聊聊預(yù)編譯吧。先討論預(yù)編譯在不同環(huán)境發(fā)生的情況下,是如何進(jìn)行預(yù)編譯的。

  • 發(fā)生在代碼執(zhí)行之前

(1)聲明提升

console.log(b);
var b=123;//undefined

這里打印undefined,這不是報(bào)錯(cuò),與Refference:b is not defined不同。這是代碼執(zhí)行之前,預(yù)編譯的結(jié)果,等同于以下代碼:

var b;//聲明提升
console.log(b);//undefined
b=123;

(2)函數(shù)聲明整體提升

test();//hello123  調(diào)用函數(shù)前并沒(méi)有聲明,但是任然打印,是因?yàn)楹瘮?shù)聲明整體提升了
function test(){
    var a=123;
    console.log('hello'+a);
}

2.發(fā)生在函數(shù)執(zhí)行之前

理解這個(gè)只需要掌握四部曲:

(1)創(chuàng)建一個(gè)AO(Activation Object)

(2)找形參和變量聲明,然后將形參和變量聲明作為AO的屬性名,屬性值為undefined

(3)將實(shí)參和形參統(tǒng)一

(4)在函數(shù)體內(nèi)找函數(shù)聲明,將函數(shù)名作為AO對(duì)象的屬性名,屬性值予函數(shù)體 那么接下來(lái)就放大招了:

var global='window';
function foo(name,sex){
    console.log(name);
    function name(){};
    console.log(name);
    var nums=123;
    function nums(){};
    console.log(nums);
    var fn=function(){};
    console.log(fn);
}
foo('html');

這里的結(jié)果是什么呢?分析如下:

//從上到下
//1、創(chuàng)建一個(gè)AO(Activation Object)
AO:{
    //2、找形參和變量聲明,然后將形參和變量聲明作為AO的屬性名,屬性值為undefined
    name:undefined,
    sex:undefined,
    nums=undefined,
    fn:undefined,
    //3、將實(shí)參和形參統(tǒng)一
    name:html,
    sex:undefined,
    nums=123,
    fn:function(){},
    //4、在函數(shù)體內(nèi)找函數(shù)聲明,將函數(shù)名作為AO對(duì)象的屬性名,屬性值予函數(shù)體
    name:function(){},
    sex:undefined,
    fn:function(){},
    nums:123//這里不僅存在nums變量聲明,也存在nums函數(shù)聲明,但是取前者的值
    以上步驟得到的值,會(huì)按照后面步驟得到的值覆蓋前面步驟得到的值
}
//依次打印
//[Function: name]
//[Function: name]
//123
//[Function: fn]

3.發(fā)生在全局(內(nèi)層作用域可以訪問(wèn)外層作用域)

同發(fā)生在函數(shù)執(zhí)行前一樣,發(fā)生在全局的預(yù)編譯也有自己的三部曲:

(1)創(chuàng)建GO(Global Object)對(duì)象

(2)找全局變量聲明,將變量聲明作為GO的屬性名,屬性值為undefined

(3)在全局找函數(shù)聲明,將函數(shù)名作為GO對(duì)象的屬性名,屬性值賦予函數(shù)體

舉個(gè)栗子:

var global='window';
function foo(a){
    console.log(a);
    console.log(global);
    var b;
}
var fn=function(){};
console.log(fn);
foo(123);
console.log(b);

這個(gè)例子比較簡(jiǎn)單,一樣的步驟和思路,就不在贅述分析了,相信你已經(jīng)會(huì)了。打印結(jié)果依次是:

[Function: fn]
123
window
ReferenceError: b is not defined

好啦,進(jìn)入正軌,我們接著說(shuō)作用域鏈。

三、作用域鏈

作用域鏈就可以幫我們找到,為什么內(nèi)層可以訪問(wèn)到外層,而外層訪問(wèn)不到內(nèi)層?但是同樣的,在認(rèn)識(shí)作用域鏈之前,我們需要見(jiàn)識(shí)見(jiàn)識(shí)一些更加晦澀抽象的名詞。

執(zhí)行期上下文:當(dāng)函數(shù)執(zhí)行的時(shí)候,會(huì)創(chuàng)建一個(gè)稱(chēng)為執(zhí)行期上下文的對(duì)象(AO對(duì)象),一個(gè)執(zhí)行期上下文定義了一個(gè)函數(shù)執(zhí)行時(shí)的環(huán)境。 函數(shù)每次執(zhí)行時(shí),對(duì)應(yīng)的執(zhí)行上下文都是獨(dú)一無(wú)二的,所以多次調(diào)用一個(gè)函數(shù)會(huì)導(dǎo)致創(chuàng)建多個(gè)執(zhí)行期上下文,當(dāng)函數(shù)執(zhí)行完畢,它所產(chǎn)生的執(zhí)行期上下文會(huì)被銷(xiāo)毀。

查找變量:從作用域鏈的頂端依次往下查找。

 [[scope]]:作用域?qū)傩裕卜Q(chēng)為隱式屬性,僅支持引擎自己訪問(wèn)。函數(shù)作用域,是不可訪問(wèn)的,其中存儲(chǔ)了運(yùn)行期上下文的結(jié)合。

我們先看一眼函數(shù)的自帶屬性:

function test(){//函數(shù)被創(chuàng)建的那一刻,就攜帶name,prototype屬性
      console.log(123);
}
console.log(test.name);//test
console.log(test.prototype);//{} 原型
// console.log(test[[scope]]);訪問(wèn)不到,作用域?qū)傩?,也稱(chēng)為隱式屬性
// test() --->AO:{}執(zhí)行完畢會(huì)回收
// test() --->AO:{}執(zhí)行完畢會(huì)回收

接下來(lái)看看作用域鏈怎么實(shí)現(xiàn)的:

var global='window';
function foo(){
    function fn(){
        var fn=222;
    }
    var foo=111;
    console.log(foo);
}
foo();

分析:

GO:{
    foo:function(){}
}
fooAO:{
    foo:111,
    fn:function(){}
}
fnAO:{
    fn:222
}
// foo定義時(shí) foo.[[scope]]---->0:GO{}
// foo執(zhí)行時(shí) foo.[[scope]]---->0:AO{}  1:GO{}  后訪問(wèn)的在前面
//fn定義時(shí) fn.[[scope]]---->0:fnAO{} 1:fooAO{}  2:GO{}
fnAO:fn的AO對(duì)象;fooAO:foo的AO對(duì)象

綜上而言:作用域鏈就是[[scope]]中所存儲(chǔ)的執(zhí)行期上下文對(duì)象的集合,這個(gè)集合呈鏈?zhǔn)芥溄?,我們把這種鏈?zhǔn)芥溄咏凶鲎饔糜蜴湣?/p>

以上就是js作用域及作用域鏈工作引擎的詳細(xì)內(nèi)容,更多關(guān)于js作用域作用域鏈的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript嚴(yán)格模式use strict的介紹

    JavaScript嚴(yán)格模式use strict的介紹

    這篇文章主要介紹了JavaScript嚴(yán)格模式use strict,嚴(yán)格模式是JavaScript中的一種限制性更強(qiáng)的變種方式。嚴(yán)格模式并不是JavaScript中的子集,它在語(yǔ)義上與正常的代碼有明顯的差異,下面我們就一起來(lái)學(xué)習(xí)該內(nèi)容吧,需要的朋友也可以參考一下
    2021-12-12
  • TypeScript?泛型推斷實(shí)現(xiàn)示例詳解

    TypeScript?泛型推斷實(shí)現(xiàn)示例詳解

    這篇文章主要為大家介紹了TypeScript?泛型推斷實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • html下載本地

    html下載本地

    html下載本地...
    2006-06-06
  • 客戶端靜態(tài)頁(yè)面玩分頁(yè)

    客戶端靜態(tài)頁(yè)面玩分頁(yè)

    客戶端靜態(tài)頁(yè)面玩分頁(yè)...
    2006-06-06
  • 微信小程序 tabs選項(xiàng)卡效果的實(shí)現(xiàn)

    微信小程序 tabs選項(xiàng)卡效果的實(shí)現(xiàn)

    這篇文章主要介紹了微信小程序 tabs選項(xiàng)卡效果的實(shí)現(xiàn)的相關(guān)資料,微信小程序內(nèi)部組件沒(méi)有Tabs 選項(xiàng)卡的功能,自己實(shí)現(xiàn)個(gè)類(lèi)似的,需要的朋友可以參考下
    2017-01-01
  • 微信小程序 wxapp地圖 map詳解

    微信小程序 wxapp地圖 map詳解

    這篇文章主要介紹了微信小程序 wxapp地圖 map基礎(chǔ)知識(shí)的相關(guān)資料,并附簡(jiǎn)單實(shí)例,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下
    2016-10-10
  • Canvaskit快速入門(mén)教程

    Canvaskit快速入門(mén)教程

    這篇文章主要為大家介紹了Canvaskit快速入門(mén)教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • JS前端可視化GraphQL使用詳解

    JS前端可視化GraphQL使用詳解

    這篇文章主要為大家介紹了JS前端可視化GraphQL使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 微信小程序 表單Form實(shí)例詳解(附源碼)

    微信小程序 表單Form實(shí)例詳解(附源碼)

    這篇文章主要介紹了微信小程序 表單Form實(shí)例詳解的相關(guān)資料,這里對(duì)form 表單進(jìn)行了詳細(xì)介紹,并附實(shí)例代碼,需要的朋友可以參考下
    2016-12-12
  • 微信小程序之?dāng)?shù)據(jù)雙向綁定與數(shù)據(jù)操作

    微信小程序之?dāng)?shù)據(jù)雙向綁定與數(shù)據(jù)操作

    這篇文章主要介紹了微信小程序之?dāng)?shù)據(jù)雙向綁定與數(shù)據(jù)操作的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評(píng)論