摘要:被你忽略的尾調(diào)用尾調(diào)用是什么在有一個(gè)新特性尾調(diào)用用最簡單的一句話描述就是某個(gè)函數(shù)的最后一步再調(diào)用另一個(gè)函數(shù),聽起來挺簡單的,但是它的功能特別強(qiáng)大,直接給你擼個(gè)例子吧。如果函數(shù)內(nèi)部還調(diào)用函數(shù),那就還有一個(gè)的調(diào)用記錄棧,以此類推。
title: 被你忽略的‘尾調(diào)用’
date: 2017-05-02 16:52:22
在ES6有一個(gè)新特性:尾調(diào)用
用最簡單的一句話描述就是‘某個(gè)函數(shù)的最后一步再調(diào)用另一個(gè)函數(shù)’,聽起來挺簡單的,
但是它的功能特別強(qiáng)大,直接給你擼個(gè)例子吧。
function a(x) { return b(x); }
這個(gè)函數(shù)的最后一步再調(diào)用另一個(gè)函數(shù),這就是尾調(diào)用。
以下幾點(diǎn)不屬于尾調(diào)用
在調(diào)用函數(shù)b之后還存在賦值的操作
function a(x) { let m = b(x); return m; }
返回的那個(gè)函數(shù)沒有加return
function a(x) { b(x); }
在調(diào)用之后還存在其他的賦值操作
function a(x) { return b(x) - 2; }尾調(diào)用優(yōu)化
函數(shù)調(diào)用會(huì)在內(nèi)存形成一個(gè)"調(diào)用記錄",又稱"調(diào)用幀"(call frame),保存調(diào)用位置
和內(nèi)部變量等信息。如果在函數(shù)A的內(nèi)部調(diào)用函數(shù)B,那么在A的調(diào)用記錄上方,還會(huì)形成
一個(gè)B的調(diào)用記錄。等到B運(yùn)行結(jié)束,將結(jié)果返回到A,B的調(diào)用記錄才會(huì)消失。如果函數(shù)B
內(nèi)部還調(diào)用函數(shù)C,那就還有一個(gè)C的調(diào)用記錄棧,以此類推。所有的調(diào)用記錄,就形成一個(gè)
"調(diào)用棧"
來個(gè)例子吧
function a() { let p = 2; let q = 3; return b(p + q) } a();
仔細(xì)觀察上面的代碼就會(huì)發(fā)現(xiàn)啊a函數(shù)似乎是多余的吧,因?yàn)閎函數(shù)是尾調(diào)用函數(shù),執(zhí)行到
這里函數(shù)a早就結(jié)束了,完全可以刪除a函數(shù)了只保留b的調(diào)用幀即可。
尾調(diào)用優(yōu)化:就是只保留內(nèi)層函數(shù)的調(diào)用幀,如果所有函數(shù)都是尾調(diào)用,那么完全可以
做到每次執(zhí)行時(shí)調(diào)用幀只能有一項(xiàng),將大大節(jié)省內(nèi)存,也就是尾調(diào)用的意義所在了。
注意的一點(diǎn)就是內(nèi)層函數(shù)運(yùn)用了外層函數(shù)的變量便不能進(jìn)行尾調(diào)用優(yōu)化了。記住哦!
顧名思義,在一個(gè)尾調(diào)用中,如果函數(shù)最后的尾調(diào)用位置上是這個(gè)函數(shù)本身,則被稱為尾遞
歸。遞歸很常用,但如果沒寫好的話也會(huì)非常消耗內(nèi)存,導(dǎo)致爆棧。但是對于尾遞歸來說只
存在一個(gè)調(diào)用棧,便永遠(yuǎn)不會(huì)發(fā)生“棧溢出”錯(cuò)誤。
就以求一個(gè)給出數(shù)的階乘來探索吧。在傳統(tǒng)的做法中利用n的遞減乘上原函數(shù),這樣復(fù)雜度
便會(huì)很高,數(shù)據(jù)量一大便會(huì)發(fā)生“棧溢出”的錯(cuò)誤了。
傳統(tǒng)的解決辦法
function f(n) { if(n === 1) { return 1; } return n * f(n -1); }
尾調(diào)用
function a(n, t) { if(n === 1) { return t; } return a(n - 1, n * t) }
對比兩個(gè)解決辦法的復(fù)雜度就知道,尾調(diào)用只保留了一個(gè)記錄。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91720.html
摘要:是捕捉異常的神器,不管是調(diào)試還是防止軟件崩潰,都離不開它。今天筆者介紹一下加上后的執(zhí)行順序嗯按順序執(zhí)行了?,F(xiàn)在筆者在語句塊中故意報(bào)錯(cuò)看來,和的都需要先經(jīng)過。 try-catch是捕捉異常的神器,不管是調(diào)試還是防止軟件崩潰,都離不開它。今天筆者介紹一下加上finally后的執(zhí)行順序 function test() { try { console.log(1); } fin...
摘要:是捕捉異常的神器,不管是調(diào)試還是防止軟件崩潰,都離不開它。今天筆者介紹一下加上后的執(zhí)行順序嗯按順序執(zhí)行了?,F(xiàn)在筆者在語句塊中故意報(bào)錯(cuò)看來,和的都需要先經(jīng)過。 try-catch是捕捉異常的神器,不管是調(diào)試還是防止軟件崩潰,都離不開它。今天筆者介紹一下加上finally后的執(zhí)行順序 function test() { try { console.log(1); } fin...
摘要:每個(gè)函數(shù)調(diào)用都將開辟出一小塊稱為堆棧幀的內(nèi)存。當(dāng)?shù)诙€(gè)函數(shù)開始執(zhí)行,堆棧幀增加到個(gè)。當(dāng)這個(gè)函數(shù)調(diào)用結(jié)束后,它的幀會(huì)從堆棧中退出。保持堆棧幀跟蹤函數(shù)調(diào)用的狀態(tài),并將其分派給下一個(gè)遞歸調(diào)用迭。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個(gè)流淌著滬江血液的純粹工程:認(rèn)真,是 HTM...
摘要:根據(jù)該規(guī)則,返回第個(gè)斐波那契數(shù)。尾遞歸函數(shù)調(diào)用自身,稱為遞歸。一個(gè)前端眼中的斐波那契數(shù)列解斐波那契數(shù)列的實(shí)用解法調(diào)用棧尾遞歸和手動(dòng)優(yōu)化尾調(diào)用優(yōu)化譯我從用寫斐波那契生成器中學(xué)到的令人驚訝的件事 斐波那契數(shù)列是以下一系列數(shù)字: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ... 在種子數(shù)字 0 和 1 ...
摘要:如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時(shí),調(diào)用幀只有一項(xiàng),這將大大節(jié)省內(nèi)存。等同于等同于注意,只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會(huì)取代外層函數(shù)的調(diào)用幀,否則就無法進(jìn)行尾調(diào)用優(yōu)化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數(shù)參數(shù)的默認(rèn)值 1.1 用法 在ES6之前是不能為...
閱讀 2113·2021-11-11 16:55
閱讀 3182·2021-10-11 10:58
閱讀 3060·2021-09-13 10:28
閱讀 3996·2021-07-26 23:57
閱讀 1042·2019-08-30 15:56
閱讀 1340·2019-08-29 13:15
閱讀 1278·2019-08-26 18:18
閱讀 1284·2019-08-26 13:44