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