欧美精品在线一区二区三区_亚洲女同精品视频_日韩一区免费_国产欧美久久久精品免费_国产这里只有精品_僵尸再翻生在线观看_久久99精品国产一区二区三区_亚洲免费一区二区_女教师淫辱の教室蜜臀av软件_中文字幕国产一区二区

JavaScript 中匿名函數的遞歸調用

2016-9-27    藍藍設計的小編

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

不管是什么編程語言,相信稍微寫過幾行代碼的同學,對遞歸都不會陌生。 以一個簡單的階乘計算為例:

function factorial(n) { if (n <= 1) { return 1;
    } else { return n * factorial(n-1);
    }
}

我們可以看出,遞歸就是在函數內部調用對自身的調用。 那么問題來了,我們知道在Javascript中,有一類函數叫做匿名函數,沒有名稱,怎么調用呢?當然你可以說,可以把匿名函數賦值給一個常量:

const factorial = function(n){ if (n <= 1) { return 1;
    } else { return n * factorial(n-1);
    }
}

這當然是可以的。但是對于一些像,函數編寫時并不知道自己將要賦值給一個明確的變量的情況時,就會遇到麻煩了。如:

(function(f){
    f(10);
})(function(n){ if (n <= 1) { return 1;
    } else { return n * factorial(n-1);//太依賴于上下文變量名 }
}) //Uncaught ReferenceError: factorial is not defined(…)

那么存不存在一種完全不需要這種給予準確函數名(函數引用變量名)的方式呢?

arguments.callee

我們知道在任何一個function內部,都可以訪問到一個叫做arguments的變量。

(function(){console.dir(arguments)})(1,2)

1.png

打印出這個arguments變量的細節,可以看出他是Arguments的一個實例,而且從數據結構上來講,他是一個類數組。他除了類數組的元素成員和length屬性外,還有一個callee方法。 那么這個callee方法是做什么的呢?我們來看下MDN

callee 是 arguments 對象的屬性。在該函數的函數體內,它可以指向當前正在執行的函數。當函數是匿名函數時,這是很有用的, 比如沒有名字的函數表達式 (也被叫做”匿名函數”)。

哈哈,很明顯這就是我們想要的。接下來就是:

(function(f){ console.log(f(10));
})(function(n){ if (n <= 1) { return 1;
    } else { return n * arguments.callee(n-1);
    }
}) //output: 3628800

但是還有一個問題,MDN的文檔里明確指出

警告:在 ECMAScript 第五版 (ES5) 的 嚴格模式 中禁止使用 arguments.callee()。

哎呀,原來在ES5的use strict;中不給用啊,那么在ES6中,我們換個ES6的arrow function寫寫看:

((f) => console.log(f(10)))( (n) => n <= 1? 1: arguments.callee(n-1)) //Uncaught ReferenceError: arguments is not defined(…)

有一定ES6基礎的同學,估計老早就想說了,箭頭函數就是個簡寫形式的函數表達式,并且它擁有詞法作用域的this值(即不會新產生自己作用域下的thisargumentssuper 和 new.target等對象),且都是匿名的。

那怎么辦呢?嘿嘿,我們需要借助一點FP的思想了。

Y組合子

關于Y Combinator的文章可謂數不勝數,這個由師從希爾伯特的著名邏輯學家Haskell B.Curry(Haskell語言就是以他命名的,而函數式編程語言里面的Curry手法也是以他命名)“發明”出來的組合算子(Haskell是研究組合邏輯(combinatory logic)的)仿佛有種神奇的魔力,它能夠算出給定lambda表達式(函數)的不動點。從而使得遞歸成為可能。

這里需要告知一個概念不動點組合子

不動點組合子(英語:Fixed-point combinator,或不動點算子)是計算其他函數的一個不動點的高階函數。

函數f的不動點是一個值x使得f(x) = x。例如,0和1是函數 f(x) = x^2 的不動點,因為 0^2 = 0而 1^2 = 1。鑒于一階函數(在簡單值比如整數上的函數)的不動點是個一階值,高階函數f的不動點是另一個函數g使得f(g) = g。那么,不動點算子是任何函數fix使得對于任何函數f都有

f(fix(f)) = fix(f). 不動點組合子允許定義匿名的遞歸函數。它們可以用非遞歸的lambda抽象來定義.

在無類型lambda演算中眾所周知的(可能是最簡單的)不動點組合子叫做Y組合子。

接下來,我們通過一定的演算推到下這個Y組合子。

// 首先我們定義這樣一個可以用作求階乘的遞歸函數 const fact = (n) => n<=1?1:n*fact(n-1)  
console.log(fact(5)) //120 // 既然不讓這個函數有名字,我們就先給這個遞歸方法一個叫做self的代號 // 首先是一個接受這個遞歸函數作為參數的一個高階函數 const fact_gen = (self) => (n) => n<=1?1:n*self(n-1)  
console.log(fact_gen(fact)(5)) //120 // 我們是將遞歸方法和參數n,都傳入遞歸方法,得到這樣一個函數 const fact1 = (self, n) => n<=1?1:n*self(self, n-1)  
console.log(fact1(fact1, 5)) //120 // 我們將fact1 柯理化,得到fact2 const fact2 = (self) => (n) => n<=1?1:n*self(self)(n-1)  
console.log(fact2(fact2)(5)) //120 // 驚喜的事發生了,如果我們將self(self)看做一個整體 // 作為參數傳入一個新的函數: (g)=> n<= 1? 1: n*g(n-1) const fact3 = (self) => (n) => ((g)=>n <= 1?1:n*g(n-1))(self(self))  
console.log(fact3(fact3)(5)) //120 // fact3 還有一個問題是這個新抽離出來的函數,是上下文有關的 // 他依賴于上文的n, 所以我們將n作為新的參數 // 重新構造出這么一個函數: (g) => (m) => m<=1?1:m*g(m-1) const fact4 = (self) => (n) => ((g) => (m) => m<=1?1:m*g(m-1))(self(self))(n)  
console.log(fact4(fact4)(5)) // 很明顯fact4中的(g) => (m) => m<=1?1:m*g(m-1) 就是 fact_gen // 這就很有意思啦,這個fact_gen上下文無關了, 可以作為參數傳入了 const weirdFunc = (func_gen) => (self) => (n) => func_gen(self(self))(n)  
console.log(weirdFunc(fact_gen)(weirdFunc(fact_gen))(5)) //120 // 此時我們就得到了一種Y組合子的形式了 const Y_ = (gen) => (f) => (n)=> gen(f(f))(n) // 構造一個階乘遞歸也很easy了 const factorial = Y_(fact_gen)  
console.log(factorial(factorial)(5)) //120 // 但上面這個factorial并不是我們想要的 // 只是一種fact2,fact3,fact4的形式 // 我們肯定希望這個函數的調用是factorial(5) // 沒問題,我們只需要把定義一個 f' = f(f) = (f)=>f(f) // eg. const factorial = fact2(fact2) const Y = gen => n => (f=>f(f))(gen)(n)  
console.log(Y(fact2)(5)) //120  console.log(Y(fact3)(5)) //120  console.log(Y(fact4)(5)) //120

推導到這里,是不是已經感覺到脊背嗖涼了一下,反正筆者我第一次接觸在康托爾、哥德爾、圖靈——永恒的金色對角線這篇文章里接觸到的時候,整個人瞬間被這種以數學語言去表示程序的方式所折服。

來,我們回憶下,我們最終是不是得到了一個不定點算子,這個算子可以找出一個高階函數的不動點f(Y(f)) = Y(f)。 將一個函數傳入一個算子(函數),得到一個跟自己功能一樣,但又并不是自己的函數,這個說法有些拗口,但又味道十足。

好了,我們回到最初的問題,怎么完成匿名函數的遞歸呢?有了Y組合子就很簡單了:

/*求不動點*/ (f => f(f)) /*以不動點為參數的遞歸函數*/ (fact => n => n <= 1 ? 1 : n * fact(fact)(n - 1)) /*遞歸函數參數*/ (5) // 120

曾經看到過一些說法是”最讓人沮喪是,當你推導出它(Y組合子)后,完全沒法兒通過只看它一眼就說出它到底是想干嘛”,而我恰恰認為這就是函數式編程的魅力,也是數學的魅力所在,精簡優雅的公式,背后隱藏著復雜有趣的推導過程。

2.jpg

總結

務實點兒講,匿名函數的遞歸調用,在日常的js開發中,用到的真的很少。把這個問題拿出來講,主要是想引出對arguments的一些講解和對Y組合子這個概念的一個普及。

但既然講都講了,我們真的用到的話,該怎么選擇呢?來,我們喜聞樂見的benchmark下: 分別測試:

// fact  fact(10) // Y (f => f(f))(fact => n => n <= 1 ? 1 : n * fact(fact)(n - 1))(10) // Y' const fix = (f) => f(f) const ygen = fix(fact2)  
ygen(10) // callee (function(n) {n<=1?1:n*arguments.callee(n-1)})(10)

環境:Macbook pro(2.5 GHz Intel Core i7), node-5.0.0(V8:4.6.85.28) 結果:

fact x 18,604,101 ops/sec ±2.22% (88 runs sampled)

Y x 2,799,791 ops/sec ±1.03% (87 runs sampled)

Y’ x 3,678,654 ops/sec ±1.57% (77 runs sampled)

callee x 2,632,864 ops/sec ±0.99% (81 runs sampled)

可見Y和callee的性能相差不多,因為需要臨時構建函數,所以跟直接的fact遞歸調用有差不多一個數量級的差異,將不定點函數算出后保存下來,大概會有一倍左右的性能提升。

 

藍藍設計m.ocunn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務 

 

日歷

鏈接

個人資料

藍藍設計的小編 http://m.ocunn.cn

存檔

日韩电影一区二区三区| 精品国内亚洲在观看18黄 | 激情小视频在线| 伊人久久中文字幕| 五月天婷婷色综合| 国产第一页精品| 三级黄色片网站| 少妇熟女视频一区二区三区| 99久久精品无码一区二区毛片| 国产精品久久激情| 欧美最顶级的aⅴ艳星| 亚洲综合久久久| 日韩成人一级大片| 亚洲美女一区| 精品二区视频| 欧美日韩网站| 欧美jjzz| 黄色综合网站| 激情视频一区二区三区| 在线观看国产精品入口| 91日韩视频| 中文字幕一区久久| 一区二区三欧美| 亚洲国产精品久久久| 精品美女一区二区| 亚洲第一区第一页| 亚洲国产精品va在线| 亚洲精品一区二区三区在线观看 | 黑人狂躁日本娇小| 无码人中文字幕| 麻豆精品国产免费| 欧美黄片一区二区三区| 特级片在线观看| 欧美精品乱码视频一二专区| 欧美黑人一级片| 日韩乱码人妻无码中文字幕| 国产情侣在线视频| 亚洲第一网站在线观看| 波多野结衣高清视频| 国产精品乱码久久久久久| 欧美一区二区| 欧美在线首页| 亚洲国产网站| 久久久久国产精品午夜一区| 日韩福利视频导航| 精品亚洲国产成人av制服丝袜| 久久激情五月激情| 粉嫩在线一区二区三区视频| 99久久亚洲一区二区三区青草 | 99这里只有精品| 91免费在线播放| 国产精品久久久一本精品| 亚洲色欲色欲www在线观看| 亚洲精品ww久久久久久p站| 亚洲影视在线观看| 日韩欧美精品中文字幕| 国产精品粉嫩| sm捆绑调教视频| 精品无码人妻一区二区三区品 | 中文字幕在线播| 国产麻豆免费观看| 久草在线看片| av在线播放网站| 国产v日韩v欧美v| 亚洲伦理网站| 国内黄色精品| 亚洲一区欧美二区| 国产一区二区福利视频| 91麻豆精东视频| 国产免费av高清在线| 欧亚乱熟女一区二区在线| 免费看污片网站| 1级黄色大片儿| 亚洲成人中文字幕在线| 日韩电影免费| 亚洲美女炮图| 成人性生交大片免费看96| 色综合色综合| 美国av一区二区| 欧美国产日韩亚洲一区| 精品久久久视频| 精品国产123| 欧美成人免费全部| 91传媒免费看| www.av91| 国产激情视频网站| 国产香蕉在线视频| 少妇高潮一区二区三区99小说| 999在线视频| 国产精品无码久久久久| 国产精品午夜一区二区三区| 中日韩av在线播放| 日日夜夜精品网站| 50路60路老熟妇啪啪| 亚洲专区区免费| 麻豆成人免费视频| 天堂а在线中文在线无限看推荐| 高清电影在线免费观看| jizz18欧美18| 国产精品综合| 亚洲国产成人午夜在线一区| 在线不卡一区二区| 久久久久久91| 欧美日韩另类丝袜其他| 日本 片 成人 在线| 午夜精品久久久久99蜜桃最新版| 亚洲在线观看av| 色网站在线看| 激情小说亚洲图片| 热久久国产精品| 一区二区三区91| 亚洲精品电影在线观看| 青青草原一区二区| 国产成人三级视频| 中文字幕一区二区三区乱码不卡| 91丝袜一区二区三区| 美丽的姑娘在线观看免费动漫| 日本国产欧美| 欧美日韩91| 久久久电影一区二区三区| 欧美日韩国产另类一区| 欧美精品免费在线观看| 九九九九久久久久| www.这里只有精品| 欧美一区二区激情视频| 国产小视频在线播放| 一区三区自拍| 日韩在线a电影| 亚洲美女偷拍久久| 中文字幕在线日韩| 久久亚洲午夜电影| 亚洲性图第一页| 一起草av在线| 97人人在线视频| 综合久久婷婷| 中文字幕欧美激情| 日韩激情在线视频| 9a蜜桃久久久久久免费| 亚洲成人天堂网| 国产伦精品一区二区三区视频我| 欧美a在线看| 国模精品一区| 欧美国产日韩精品免费观看| 亚洲欧洲国产一区| 久久精品二区| 白丝女仆被免费网站| 欧美熟妇另类久久久久久不卡 | 精品久久久久久久久久久久久久久久久| 国产成人综合av| 久久9精品区-无套内射无码| 日韩黄色a级片| www在线免费观看视频| 欧美第十八页| 中文字幕一区二区三区四区| 日韩中文字幕视频在线| 制服诱惑一区| 欧洲第一无人区观看| 男女视频在线观看| 激情婷婷综合| 亚洲柠檬福利资源导航| 伊人伊成久久人综合网小说| 欧美精品一区在线| 免费成人深夜天涯网站| 国产二区在线播放| 亚洲h色精品| 午夜激情一区二区三区| 国产999精品久久久| 亚洲免费av一区二区三区| 亚洲国产无线乱码在线观看| 国产精品扒开腿做爽爽爽视频软件| 丝袜美腿高跟呻吟高潮一区| 欧美日韩久久久久久| 99精彩视频在线观看免费| 久久国产劲爆∧v内射| 亚洲欧美综合一区二区| 色天天色综合| 亚洲精品欧美激情| 91av在线看| 日韩成人精品视频在线观看| 亚洲成人777777| 久久97久久97精品免视看秋霞| 国产亚洲欧美日韩在线一区| 精品国内亚洲在观看18黄| 国产av人人夜夜澡人人爽麻豆| 免费看污视频的网站| 日韩精品一区二区三区av| 国产伦精品一区二区三区免费| 亚洲精品国产综合久久| 综合久久国产| 亚洲 欧美 中文字幕| 九七电影院97理论片久久tvb| 国产成人a级片| 主播福利视频一区| 欧美日韩精品在线一区二区 | 日本精品一区二区三区高清 久久 日本精品一区二区三区不卡无字幕 | 牛牛精品在线视频| 日本亚洲三级在线| 亚洲第一男人av| 亚洲国产一二三精品无码| www.国产一区二区| 秋霞一区二区| 亚洲激情一二三区| 91夜夜未满十八勿入爽爽影院| 欧美熟妇一区二区| 成视频免费观看在线看| 麻豆一区二区在线| 亚洲欧洲美洲在线综合| 婷婷五月综合缴情在线视频| www.国产视频| 日韩电影免费网址| 在线视频你懂得一区| 欧美日韩一区在线播放| 日韩在线视频免费播放| 麻豆精品久久| 一级中文字幕一区二区| 成人啪啪免费看| 婷婷久久综合网| 久久精品国产精品亚洲毛片| 欧美国产亚洲另类动漫| 国产精品av电影| 久久精品—区二区三区舞蹈| 黄色羞羞视频在线观看| 成人的网站免费观看| 欧美国产精品va在线观看| 99re6在线观看| 美州a亚洲一视本频v色道| 亚洲在线观看| 尤物九九久久国产精品的分类| 9久久婷婷国产综合精品性色| 完全免费av在线播放| 久久亚洲风情| 国产亚洲一区二区精品| 92看片淫黄大片一级| 亚洲人在线观看视频| 亚洲作爱视频| 中文字幕在线看视频国产欧美| 精品久久久久久无码国产| 桃花色综合影院| 奇米色777欧美一区二区| 中文字幕欧美日韩在线| 亚洲精品一二三四| 丁香花高清在线观看完整版| 91丨九色丨蝌蚪丨老版| 国产精品三级美女白浆呻吟| a级黄色片免费看| 成人av动漫| 欧美色老头old∨ideo| 日本三日本三级少妇三级66| 四虎免费在线观看| 欧美一级久久| 欧美另类暴力丝袜| 国产美女视频免费观看下载软件| 美女高潮视频在线看| 久久久99精品久久| 91传媒视频免费| 成人午夜淫片100集| 欧美色网址大全| 日韩美女一区二区三区| 久久久精品在线视频| 美女写真理伦片在线看| 久久影院午夜片一区| 91传媒在线免费观看| 精品一区二三区| 国内精品久久久久久久影视麻豆 | 亚洲欧美日韩偷拍| xxxxxx欧美| 亚洲综合免费观看高清完整版在线 | 国产精品成人播放| 久久精品国产亚洲av无码娇色| 精品国产午夜肉伦伦影院| 欧美精品粉嫩高潮一区二区| 久章草在线视频| 性xxxxfjsxxxxx欧美| 国产精品第五页| 亚洲 国产 日韩 综合一区| 色窝窝无码一区二区三区| 日本午夜一本久久久综合| 久久久久久久久爱| 久久精品国产亚洲av香蕉| 色综合久久一区二区三区| 亚洲人成自拍网站| 成人午夜剧场视频网站| 66精品视频在线观看| 欧美草草影院在线视频| 亚洲熟妇一区二区| 四虎国产精品免费久久| 欧美色偷偷大香| www.久久av.com| av激情成人网| 欧美三级乱人伦电影| 亚欧在线免费观看| 在线观看网站免费入口在线观看国内 | 国产高清精品软男同| 国产午夜在线视频| 国产日韩高清在线| 一区二区免费电影| 1pondo在线播放免费| 国产精品免费免费| 六月婷婷激情网| 青青青青在线| 亚洲午夜私人影院| 1024精品视频| 另类激情视频| 6080亚洲精品一区二区| 稀缺小u女呦精品呦| 99re6热只有精品免费观看| 91精品国产91久久综合桃花| 少妇极品熟妇人妻无码| www.成人网| 一道本无吗dⅴd在线播放一区| 日韩av毛片在线观看| 希岛爱理一区二区三区| 欧美国产亚洲视频| 糖心vlog精品一区二区| 麻豆精品精品国产自在97香蕉 | 精品国产区在线| 色综合成人av| 国产精品私人自拍| 亚洲色成人www永久在线观看| av资源一区| 91精品综合久久久久久| av鲁丝一区鲁丝二区鲁丝三区| 在线成人动漫av| 米奇精品一区二区三区在线观看| 欧美日韩一二三四区| 蜜桃一区二区三区在线| 精品九九九九| 天堂аⅴ在线地址8| 亚洲成人自拍一区| 久久久久国产一区| 一区二区三区在线资源| 精品国模在线视频| 国产精品熟女视频| 国产精品99久久久久| 亚洲最大色综合成人av| 美足av综合网| 日韩欧美一区二区视频| 成人精品一二三区| 99亚洲精品| 国产精品视频免费一区| 幼a在线观看| 91久久精品国产91性色tv| 182在线视频| 欧美大黑bbbbbbbbb在线| 国产精品成人va在线观看| 中文字幕高清在线| 五月激情综合网| 中文字幕在线视频播放| 亚洲精品小说| 91亚洲va在线va天堂va国| 亚洲欧洲动漫| 欧美视频精品一区| www.久久国产| 亚洲理论在线| 蜜桃传媒视频麻豆一区 | 色猫猫成人app| 国产亚洲欧美aaaa| 亚洲 日本 欧美 中文幕| 成人18视频在线播放| 在线观看污视频| 成人国产精品久久| 欧美xxxx做受欧美| 好吊视频一区二区三区| 亚洲欧美福利一区二区| 中文字幕无码毛片免费看| 精品成av人一区二区三区| 国产精品欧美风情| 国产免费永久在线观看| 五月综合激情网| 亚洲а∨天堂久久精品2021| 久久久久久久高潮| 亚洲图片小说在线| 欧亚一区二区| 欧美日韩xxxxx| 国产三级av在线| 午夜视频在线观看一区| 熟妇人妻久久中文字幕| 99在线|亚洲一区二区| 日本一区二区久久精品| 日日av拍夜夜添久久免费| xxav国产精品美女主播| 欧美少妇bbw| 欧美日韩一区二区三区| 极品色av影院| 风流少妇一区二区| 九九九在线观看视频| 成人嫩草影院| 国产一区二区视频在线免费观看 | 久久男人av资源站| 综合欧美国产视频二区| 亚洲欧美黄色片| 一本大道久久a久久综合婷婷 | 99re国产在线| 综合久久久久综合| 三上悠亚影音先锋| 国产真实乱子伦精品视频| 狠狠爱免费视频| 欧美丰满老妇| 日韩中文一区| 一区三区自拍|