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

資訊專(zhuān)欄INFORMATION COLUMN

迎接ECMAScript 6, 使用尾遞歸

whatsns / 1846人閱讀

摘要:而且最的是,在,我們將迎來(lái)尾遞歸優(yōu)化,享受只有這些古典函數(shù)式語(yǔ)言才擁有的能力。使用尾遞歸這里有一個(gè)使用尾遞歸提取絕對(duì)文件名的例子,可以來(lái)展示下尾遞歸的魅力。

尾調(diào)用,是指函數(shù)內(nèi)部的最后一個(gè)動(dòng)作是函數(shù)調(diào)用。該調(diào)用的返回值,直接返回給函數(shù)。

Example:

function sum(x) {
    return sum(x + 1);
}

這里的 sum() 內(nèi)部的 sum 就是屬于尾調(diào)用,ta 所返回的值直接返回給調(diào)用 ta 的上層 sum() 函數(shù)。

function sum(x) {
    return 1 + sum(x + 1);
}

這里的 sum() 內(nèi)部的 sum 就不屬于尾調(diào)用,ta 所返回的值在返回給調(diào)用 ta 的上層 sum() 函數(shù)之前,需要先跟 1 計(jì)算和,然后再返回。

尾調(diào)用和非尾調(diào)用有什么差異?

編寫(xiě)一個(gè)求和函數(shù),有大致3種方式:

循環(huán)

function sum(x) {
    var result = x;
    while (x >= 1) {
        result += --x;
    }
    return result;
}

循環(huán)自然是速度和性能最好的,但是在編寫(xiě)復(fù)雜的代碼時(shí),循環(huán)往往模塊化很差,可讀性很差,而且無(wú)法體現(xiàn)數(shù)學(xué)上的描述。

普通遞歸

function sum(x) {
    if (x === 1) {
        return 1;
    }
    return x + sum(--x);
}

普通遞歸時(shí),內(nèi)存需要記錄調(diào)用的堆棧所出的深度和位置信息。在最底層計(jì)算返回值,再根據(jù)記錄的信息,跳回上一層級(jí)計(jì)算,然后再跳回更高一層,依次運(yùn)行,直到最外層的調(diào)用函數(shù)。在cpu計(jì)算和內(nèi)存會(huì)消耗很多,而且當(dāng)深度過(guò)大時(shí),會(huì)出現(xiàn)堆棧溢出。

比如,計(jì)算 sum(5) 的時(shí)候,其計(jì)算過(guò)程是這樣的:

sum(5)
(5 + sum(4))
(5 + (4 + sum(3)))
(5 + (4 + (3 + sum(2))))
(5 + (4 + (3 + (2 + sum(1)))))
(5 + (4 + (3 + (2 + 1))))
(5 + (4 + (3 + 3)))
(5 + (4 + 6))
(5 + 10)
15

在計(jì)算的過(guò)程中,堆棧一直不停的記錄每一層次的詳細(xì)信息,以確保該層次的操作完成,能返回到上一層次。

通過(guò)尾遞歸,可以取消過(guò)多的堆棧記錄,而只記錄最外層和當(dāng)前層的信息,完成計(jì)算后,立刻返回到最上層。從而減少 cpu 計(jì)算和內(nèi)存消耗。

尾遞歸

function sum(x, total) {
    if (x === 1) {
        return x + total;
    }
    return sum(--x, x + total);
}

這個(gè)函數(shù)更具有數(shù)學(xué)描述性:

如果輸入值是1 => 當(dāng)前計(jì)算數(shù)1 + 上一次計(jì)算的和total

如果輸入值是x => 當(dāng)前計(jì)算數(shù)x + 上一次計(jì)算的和total

計(jì)算 sum(5, 0)的時(shí)候,其過(guò)程是這樣的:

sum(5, 0)
sum(4, 5)
sum(3, 9)
sum(2, 12)
sum(1, 14)
15

整個(gè)計(jì)算過(guò)程是線性的,調(diào)用一次 sum(x, total) 后,會(huì)進(jìn)入下一個(gè)棧,相關(guān)的數(shù)據(jù)信息和跟隨進(jìn)入,不再放在堆棧上保存。當(dāng)計(jì)算完最后的值之后,直接返回到最上層的 sum(5,0)。

這能有效的防止堆棧溢出。

  

而且最happy的是,在ECMAScript 6,我們將迎來(lái)尾遞歸優(yōu)化,享受只有LISP
HASKELL這些古典函數(shù)式語(yǔ)言才擁有的能力。通過(guò)尾遞歸優(yōu)化,javascript代碼在解釋成機(jī)器碼的時(shí)候,將會(huì)向while看起,也就是說(shuō),同時(shí)擁有數(shù)學(xué)表達(dá)能力和while的效能。

使用尾遞歸

這里有一個(gè)使用尾遞歸提取絕對(duì)文件名的例子,可以來(lái)展示下尾遞歸的魅力。這個(gè)函數(shù)需要輸入一個(gè)(或幾個(gè))目錄名和當(dāng)前所在的文件位置,然后會(huì)遞歸提取目錄下的所有文件名,放入一個(gè)棧中。

var FS = require("fs");
var PATH = require("path");

function readSync(paths, i) {
    if (i >= 0 && i < paths.length) {
        var stats = FS.statSync(paths[i]);
        if (stats.isFile()) {
            return readSync(paths, ++i);
        } else if (stats.isDirectory()) {
            var newPaths = FS.readdirSync(paths[i]).map(function (path) {
                return PATH.join(paths[i],path);
            });
            return readSync(paths.slice(0, i).concat(newPaths, 
                                                     paths.slice(i + 1)), 
                            i);
        } else {
            return readSync(paths.slice(0, i).concat(paths.slice(i + 1)), 
                            i);
        }
    } else {
        return paths;
    }
}

測(cè)試一下,這個(gè)函數(shù)可以在服務(wù)器啟動(dòng)時(shí),提取某一個(gè)(或者幾個(gè))目錄內(nèi)的所有文件,然后用于編譯或者是其他的操作。

readSync([PATH.join(__dirname, "./tpls")], 0).forEach(function (path) {
    console.log(path);
});
readSync([PATH.join(__dirname, "./tpls"), PATH.join(__dirname, "./pages")], 0).forEach(function (path) {
    console.log(path);
});

文章來(lái)源:http://www.jianshu.com/p/269ba1ba1644

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

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

相關(guān)文章

  • 《javascript語(yǔ)言精粹》學(xué)習(xí)筆記 - 遞歸函數(shù)

    摘要:遞歸函數(shù)就是會(huì)直接或者間接地調(diào)用自身的一種函數(shù)。一般來(lái)說(shuō),一個(gè)遞歸函數(shù)調(diào)用自身去解決它的子問(wèn)題。書(shū)上第二個(gè)例子是說(shuō)遞歸函數(shù)可以非常高效率的操作樹(shù)形結(jié)構(gòu),比如。有一些語(yǔ)言提供了尾遞歸的優(yōu)化。好運(yùn)的是,給我們帶來(lái)了尾遞歸,詳細(xì)迎接使用尾遞歸。 遞歸函數(shù)就是會(huì)直接或者間接地調(diào)用自身的一種函數(shù)。遞歸是一種強(qiáng)大的編程技術(shù),它把一問(wèn)題分解為一組相似的子問(wèn)題,每一個(gè)都用一個(gè)尋常解去解決。一般來(lái)...

    Ryan_Li 評(píng)論0 收藏0
  • Javascript 深入學(xué)習(xí)循環(huán)

    摘要:遞歸函數(shù)還會(huì)受到瀏覽器調(diào)用棧的大小的限制。雖然迭代也會(huì)導(dǎo)致性能問(wèn)題,但是使用優(yōu)化的循環(huán)就可以代替長(zhǎng)時(shí)間運(yùn)行的遞歸函數(shù),可以提高新能,因?yàn)檫\(yùn)行一個(gè)循環(huán)比反復(fù)調(diào)用一個(gè)函數(shù)的開(kāi)銷(xiāo)要小。 本文章記錄本人在深入學(xué)習(xí)js循環(huán)中看書(shū)理解到的一些東西,加深記憶和并且整理記錄下來(lái),方便之后的復(fù)習(xí)。 選擇正確的循環(huán)體 在大部分編程語(yǔ)言中,代碼執(zhí)行的時(shí)間多數(shù)消耗在循環(huán)的執(zhí)行上。 js定義了4種...

    Cristalven 評(píng)論0 收藏0
  • ECMAScript6 新特性——“函數(shù)的擴(kuò)展”

    摘要:返回空字符串,返回將一個(gè)具名函數(shù)賦值給一個(gè)變量,則和的屬性都返回這個(gè)具名函數(shù)原本的名字。不可以使用對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在。等到運(yùn)行結(jié)束,將結(jié)果返回到,的調(diào)用幀才會(huì)消失。 1 函數(shù)參數(shù)的默認(rèn)值 ES6允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值,即直接寫(xiě)在參數(shù)定義的后面: function log(x = message.,y = duration infomation.) { consol...

    Jiavan 評(píng)論0 收藏0
  • JS的函數(shù)調(diào)用棧有多深?

    摘要:中尾遞歸優(yōu)化支持尾遞歸優(yōu)化如果一個(gè)函數(shù)的最后一個(gè)操作是函數(shù)調(diào)用,那么將會(huì)用跳轉(zhuǎn)而不是子調(diào)用。自從年雙十一正式上線,累計(jì)處理了億錯(cuò)誤事件,付費(fèi)客戶有陽(yáng)光保險(xiǎn)核桃編程荔枝掌門(mén)對(duì)微脈青團(tuán)社等眾多知名企業(yè)。 譯者按: 有時(shí)候會(huì)遇到Maximum call stack size exceeded的問(wèn)題,本文教你stack size的計(jì)算方法。 原文: The maximum call stac...

    AprilJ 評(píng)論0 收藏0
  • ES6學(xué)習(xí) 第七章 函數(shù)的擴(kuò)展

    摘要:前言本章介紹函數(shù)的擴(kuò)展。形式為變量名,函數(shù)的最后一個(gè)命名參數(shù)以為前綴。規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值解構(gòu)賦值或者擴(kuò)展運(yùn)算符,那么函數(shù)內(nèi)部就不能顯式設(shè)定為嚴(yán)格模式,否則會(huì)報(bào)錯(cuò)。箭頭函數(shù)不能用作構(gòu)造函數(shù)。尾遞歸函數(shù)調(diào)用自身,稱(chēng)為遞歸。 前言本章介紹函數(shù)的擴(kuò)展。有些不常用的知識(shí)了解即可。本章原文鏈接:函數(shù)的擴(kuò)展。函數(shù)參...

    番茄西紅柿 評(píng)論0 收藏2637

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<