一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

用一個例子理解JS函數(shù)的底層處理機(jī)制

 丹楓無跡 2021-09-13

個人筆記,如有錯誤煩請指正

以下面代碼的運行舉例,一行行進(jìn)行運行的解析

var x = [12, 23];
function fn(y) {
    y[0] = 100;
    y = [100];
    y[1] = 200;
    console.log(y);
}
fn(x);
console.log(x);

var x = [12, 23];運行如下

  1. 開辟堆內(nèi)存,創(chuàng)建數(shù)組值,假設(shè)堆內(nèi)存的地址為0x000000
  2. 聲明變量x
  3. 賦值,即將x指向堆內(nèi)存的地址0x000000

接著

function fn(y) {
    y[0] = 100;
    y = [100];
    y[1] = 200;
    console.log(y);
}

運行如下

上面這段代碼是創(chuàng)建一個函數(shù)的過程。和創(chuàng)建一個變量類似:

  • 都是聲明一個變量存儲值
  • 步驟一樣:第一步也是先創(chuàng)建一個堆內(nèi)存,里面存的是函數(shù),這個堆內(nèi)存有一個地址,然后把地址賦值給變量
  • 聲明:方式類似函數(shù)名也算變量,當(dāng)我們聲明函數(shù)function fn(y){...}時,相當(dāng)于我們聲明了一個變量,只不過值是函數(shù)。類似于var fn = function (y){...}的函數(shù)表達(dá)式。最終把一個函數(shù)作為值賦值給一個變量或者其他

所以創(chuàng)建一個函數(shù),詳細(xì)的執(zhí)行順序如下

  1. 首先開辟一個堆內(nèi)存,存儲函數(shù)的值(假設(shè)地址為0x000001)
    • 對象的值在堆內(nèi)存當(dāng)中,存儲的是它的鍵值對
    • 函數(shù)的值在堆內(nèi)存當(dāng)中,存儲的是它的代碼,而且是以字符串的形式存儲的
    • 創(chuàng)建函數(shù)的時候,就聲明了它的作用域(scope),scope值是當(dāng)前創(chuàng)建函數(shù)的時候所處的上下文,即在哪個上下文中創(chuàng)建的,作用域就是誰
  2. 接著聲明變量fn,并且指向堆內(nèi)存地址(假設(shè)為0x000001)

函數(shù)執(zhí)行的步驟

fn(x);運行如下(函數(shù)執(zhí)行的步驟)

  1. 函數(shù)執(zhí)行時,永遠(yuǎn)傳的是值,fn(x)傳的是x的值,即x指向的0x000000堆內(nèi)存地址
  2. fn(0x000000)形成一個全新的私有上下文EC(fn)
  3. 在函數(shù)形成的新的上下文中,生成一個私有化變量對象AO,用來存儲當(dāng)前上下文中聲明的變量(Active Object活動對象,簡稱AO,變量對象的一種,類似全局上下文中的全局變量)
  4. 內(nèi)部代碼執(zhí)行之前發(fā)生的事
    • 初始化作用域鏈scope-chain <EC(fn1),EC(G)>,鏈的兩頭是 <當(dāng)前自己的私有上下文,函數(shù)的作用域(創(chuàng)建函數(shù)的時候所在的上下文)>,鏈的右側(cè)也叫當(dāng)前上下文的'上級上下文'
    • 初始化this
    • 初始化argument
    • 在當(dāng)前上下文中,聲明一個形參變量,并且把傳遞的實參值賦值給它
    • 變量提升
  5. 進(jìn)棧執(zhí)行代碼
  6. 出棧釋放

函數(shù)進(jìn)棧執(zhí)行代碼的詳細(xì)步驟

接著說說上面第5步的詳細(xì)步驟

把之前創(chuàng)建的函數(shù),在堆內(nèi)存中存儲的代碼字符串拿出來轉(zhuǎn)換為代碼一行一行的執(zhí)行執(zhí)行。

私有上下文中代碼執(zhí)行中如果遇到一個變量,首先看是否為自己的'私有變量',如果是'私有'的,則操作自己的,和外界沒有必然的關(guān)系,如果不是自己私有的,則基于作用域鏈,向其上級上下文中查找,看是否為上級上下文中私有的,如果也不是,繼續(xù)向上查找......一直找到EC(G)全局上下文為止,我們把這種查找過程稱之為 作用域鏈查找機(jī)制
所以

y[0] = 100
y = [100]
y[1] = 200

是這樣的執(zhí)行的:

  1. y[0] = 100,y現(xiàn)在存儲的內(nèi)存地址為0x000000,所以修改這個地址下的值:

  2. y = [100],出現(xiàn)了新的對象值,所以要開辟新的堆內(nèi)存0x000002,創(chuàng)建值,賦值

  3. y[1] = 200,將0x000002地址對應(yīng)的對象的值進(jìn)行修改

  4. console.log(y);這個y就是0x000002對應(yīng)的值[100,200]操作的是私有變量y

fn函數(shù)至此執(zhí)行完畢。

接著執(zhí)行外面的console.log(x);,此時的x為全局變量對象中的x,對應(yīng)的地址為0x000000,所以直接進(jìn)行輸出[100,23]

如果fn執(zhí)行完之后,繼續(xù)執(zhí)行其他函數(shù),同樣會經(jīng)歷這樣的流程。形成新的上下文,進(jìn)棧執(zhí)行...如果函數(shù)非常多,會一直進(jìn)棧,占內(nèi)存會越來越大。所以為了優(yōu)化,瀏覽器會默認(rèn)做出很多回收機(jī)制

結(jié)果與總體流程

結(jié)果

總體流程圖

其他說明點

js上下文分類

js上下文(哪一個區(qū)域下執(zhí)行)分類

  • 全局上下文EC(G)
  • 函數(shù)執(zhí)行形成的私有上下文
  • 塊級私有上下文

什么是私有變量

私有變量是私有上下文聲明的變量,包含

  1. 形參
  2. 代碼執(zhí)行的時候聲明的變量var / let / const / function ...
    注意與全局變量區(qū)別,沒有直接關(guān)系,但是可能會存在一些間接關(guān)系,比如下面這段代碼下全局變量x的值是0x000000,通過函數(shù),將0x000000傳給了私有變量y,y也是0x000000
function fn(y) {
    y[0] = 100;
    y = [100];
    y[1] = 200;
    console.log(y);
}
fn(x)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    五月婷婷亚洲综合一区| 老司机亚洲精品一区二区| 欧美日本亚欧在线观看| 视频在线观看色一区二区| 成年女人下边潮喷毛片免费| 日韩精品日韩激情日韩综合| 美国黑人一级黄色大片| 亚洲高清亚洲欧美一区二区| 欧美精品久久男人的天堂| 天海翼高清二区三区在线| 麻豆视传媒短视频免费观看| 日本加勒比在线观看一区| 91老熟妇嗷嗷叫太91| 高清一区二区三区四区五区| 国产一区二区三区四区中文| 人妻亚洲一区二区三区| 日本婷婷色大香蕉视频在线观看| 日韩一级毛一欧美一级乱| 成人你懂的在线免费视频| 国产午夜精品久久福利 | 粉嫩内射av一区二区| 五月天丁香亚洲综合网| 日韩欧美一区二区亚洲| 国产又粗又猛又长又大| 久久香蕉综合网精品视频| 日本人妻熟女一区二区三区 | 国产一区二区三区四区中文| 国产又粗又硬又长又爽的剧情| 99国产成人免费一区二区| 好吊视频一区二区在线| 91在线国内在线中文字幕| 五月婷婷缴情七月丁香| 少妇淫真视频一区二区| 色婷婷视频免费在线观看| 国内欲色一区二区三区| 国产亚洲欧美日韩精品一区| 欧美一二三区高清不卡| 国产成人一区二区三区久久| 欧美二区视频在线观看| 国产精品午夜福利免费在线| 精品国产日韩一区三区|