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

資訊專欄INFORMATION COLUMN

簡單易懂的現(xiàn)代魔法-遞歸

Joyven / 2635人閱讀

摘要:完整的一次調(diào)用流程遞歸調(diào)用棧遞歸同樣使用調(diào)用棧我們來分析下階乘的調(diào)用棧直接看圖遞歸注意事項遞歸會導(dǎo)致程序的性能變低如果遞歸嵌套很深,那么調(diào)用棧會很長,這將占用大量內(nèi)存,可能會導(dǎo)致棧溢出

平時在前端開發(fā)中,好像也沒啥用到遞歸的地方。不過這并不代表遞歸不重要,如果你看過一些框架的源碼,就會經(jīng)常見到它的影子:比如渲染虛擬DOM的render函數(shù),webpack中require依賴分析,Koa2洋蔥式的中間件模型,其實都運用到了遞歸算法。

博客原文

遞歸概念

那么遞歸到底是啥?先上兩張圖:

圖1:

圖2:

遞歸,就是在運行的過程中調(diào)用自己

我們來看個最簡單的階乘函數(shù):

5! = 5 * 4 * 3 * 2 * 1
function factorial(num) {
    if (num === 1) { // 基線條件
        return 1;
    }

    // 遞歸條件
    return num * factorial(num-1);
}

factorial(5);

一個常規(guī)的遞歸函數(shù)都有兩部分:

基線條件(if (num === 1)):保證函數(shù)不再調(diào)用自己,避免無限循環(huán)

遞歸條件(num * factorial(num-1)):保證函數(shù)能夠調(diào)用自己

調(diào)用棧

棧是一種先進后出的數(shù)據(jù)結(jié)構(gòu),它只有兩種操作,出棧和入棧

const nekopara = ["chocolat", "Coconut"];
nekopara.push("vanilla"); // 入棧
nekopara.pop(); // 出棧

代碼在運行過程中,會有一個叫做調(diào)用棧(call stack)的概念。

function greet(name) {
    console.log(`hello, ${name}!`)
    greet2(name);
    console.log(`getting ready to say bye`);
    bye();
}

function greet2(name) {
    console.log(`how are you, ${name}?`);
}

function bye() {
    console.log(`bye`);
}

greet("deepred");

調(diào)用greet("deepred")時,計算機會首先給該函數(shù)分配一塊內(nèi)存,并將變量名name設(shè)置為deepred

每當(dāng)調(diào)用函數(shù)時,都會分配一個內(nèi)存塊并將涉及到的變量值存儲到內(nèi)存中。

打印hello, deepred后,調(diào)用了greet2("deepred")。同樣,計算機再次分配了一塊內(nèi)存,并且該內(nèi)存塊位于第一個內(nèi)存塊上面。

調(diào)用棧的最上面表示當(dāng)前運行的函數(shù),如圖所示,現(xiàn)在正在運行的是greet2函數(shù),打印輸出how are you, deepred?后,函數(shù)greet2執(zhí)行完畢,棧頂?shù)膬?nèi)存塊被彈出。

現(xiàn)在棧頂?shù)膬?nèi)存塊又變回greet,這意味著我們從greet2的函數(shù)中跳出,再次返回到了greet。

我們在greet中調(diào)用了greet2時,greet只執(zhí)行了一部分。

特別注意:調(diào)用另外一個函數(shù)時,當(dāng)前函數(shù)暫停并且處于未完成狀態(tài),暫停函數(shù)的所有變量的值仍然在內(nèi)存中

執(zhí)行完greet2后,我們回到了greet,并從離開的地方開始接著往下執(zhí)行:首先打印getting ready to say bye,然后調(diào)用bye函數(shù)。

在棧頂添加了bye函數(shù)的內(nèi)存塊后,開始執(zhí)行bye函數(shù),打印bye,然后函數(shù)返回,內(nèi)存塊被彈出。

我們又再次回到了greet中,這次沒有其他要運行的代碼了,于是從greet函數(shù)中返回,內(nèi)存塊被彈出,調(diào)用棧最后為空。

完整的一次調(diào)用流程

遞歸調(diào)用棧

遞歸同樣使用調(diào)用棧

我們來分析下階乘fact(3)的調(diào)用棧

function fact(num) {
   if (num === 1) { 
       return 1;
   }
   return num * fact(num-1);
}

fact(3);

直接看圖:

遞歸注意事項

遞歸會導(dǎo)致程序的性能變低

如果遞歸嵌套很深,那么調(diào)用棧會很長,這將占用大量內(nèi)存,可能會導(dǎo)致棧溢出

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

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

相關(guān)文章

  • 用最簡單易懂道理告訴你,為什么JavaScript在現(xiàn)代引擎(V8,JavaScriptCore)

    摘要:代碼在本文最后,首先是,編譯出字節(jié)碼耗時約,運行字節(jié)碼耗時約,。也有解釋過程,字節(jié)碼需要由虛擬機解釋執(zhí)行。而引擎的做法是更接近二哥的,在編譯階段的過程是源碼抽象語法樹字節(jié)碼中間代碼。于是大量的字節(jié)碼優(yōu)化措施被延后,比如。 簡單性能測試 首先,我們先來做一個簡單的性能測試,對比一下Java,JavaScript,PHP,Ruby這四門語言。這個性能測試,是計算斐波那契數(shù)列(兔子數(shù)列)。比...

    Moxmi 評論0 收藏0
  • 手摸手教你用 js 寫一個 js 解釋器

    摘要:手摸手教你用寫一個解釋器用來編譯看起來是個高大上的東西,實際原理其實很簡單,無非就是利用對象屬性可以用字符串表示這個特性來實現(xiàn)的黑魔法罷了。 手摸手教你用 js 寫一個 js 解釋器 用 js 來 編譯 js 看起來是個高大上的東西,實際原理其實很簡單,無非就是利用 js 對象屬性可以用字符串表示 這個特性來實現(xiàn)的黑魔法罷了。之所以看起來那么 深奧, 大概是由于網(wǎng)上現(xiàn)有的教程,都是動不...

    hss01248 評論0 收藏0
  • 窺探 Script 標(biāo)簽(步入現(xiàn)代 Web 開發(fā)魔法世界)

    摘要:而且默認(rèn)帶有執(zhí)行的順序是,,即便是內(nèi)聯(lián)的,依然具有屬性。模塊腳本只會執(zhí)行一次必須符合同源策略模塊腳本在跨域的時候默認(rèn)是不帶的。通常被用作腳本被禁用的回退方案。最后標(biāo)簽真的令人感到興奮。 窺探 Script 標(biāo)簽 0x01 什么是 script 標(biāo)簽? script 標(biāo)簽允許你包含一些動態(tài)腳本或數(shù)據(jù)塊到文檔中,script 標(biāo)簽是非閉合的,你也可以將動態(tài)腳本或數(shù)據(jù)塊當(dāng)做 script 的...

    Terry_Tai 評論0 收藏0
  • 窺探 Script 標(biāo)簽(步入現(xiàn)代 Web 開發(fā)魔法世界)

    摘要:而且默認(rèn)帶有執(zhí)行的順序是,,即便是內(nèi)聯(lián)的,依然具有屬性。模塊腳本只會執(zhí)行一次必須符合同源策略模塊腳本在跨域的時候默認(rèn)是不帶的。通常被用作腳本被禁用的回退方案。最后標(biāo)簽真的令人感到興奮。 窺探 Script 標(biāo)簽 0x01 什么是 script 標(biāo)簽? script 標(biāo)簽允許你包含一些動態(tài)腳本或數(shù)據(jù)塊到文檔中,script 標(biāo)簽是非閉合的,你也可以將動態(tài)腳本或數(shù)據(jù)塊當(dāng)做 script 的...

    gaosboy 評論0 收藏0

發(fā)表評論

0條評論

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