Java教程

Javascript尾调用优化

本文主要是介绍Javascript尾调用优化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

JavaScript 尾调用优化
递归
递归函数的形式通常是一个函数通过名称调用自己

比如经典的返回斐波那契数列生成问题

function fibonacci (n) {
if (n === 1 || n === 2) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
1
2
3
4
5
6
我们求斐波那契数列的第10项时,可以轻松求出 fibonacci(10) = 55, 可是当我们要求斐波那契数列的第1000项时, fibonacci(1000) 却没那么容易求出来甚至于报错

原因就是递归的每一次调用都会推一个栈帧到调用栈中,当调用层数越来越多,调用栈中的栈帧越来越多,将调用栈都给塞满了,也就出现了堆栈溢出的报错。

这个时候我们就需要对我们的代码进行优化了:

第一种方法就是将递归改写成循环
第二种就是将介绍的尾调用优化
尾调用优化
ECMAScript 6 规范新增了一项内存管理优化机制,让 JavaScript 引擎在满足条件时可以重用栈帧。

那么什么叫 “尾调用” 呢?

即外部函数的返回值是一个内部函数的返回值。

function outerFunc () {
return innerFunc();
}
1
2
3
当执行到 outerFunc 函数体时,第一个栈帧被推入栈,

到达 return innerFunc(); 语句时,发现要返回需要先求值,于是第二个栈帧也被推到栈上,

此时会发现其实第一个栈帧似乎没什么用了,因为 innerFunc() 的返回值也是 outerFunc() 的返回值

于是会将第一个栈帧弹出,而保留第二个,也就是尾调用优化。

尾调用优化的达成条件
条件
尾调用优化的条件就是确定外部栈帧真的没必要存在了

代码在严格模式下执行

外部函数的返回值是对尾调用函数的调用

尾调用函数返回后不需要执行额外的逻辑

尾调用函数不是引用外部函数作用域中自由变量的闭包

符合尾调用优化的例子
"use strict";

function outerFunction1 () {
return innerFunction();
}

function outerFunction2 (condition) {
return condition ? innerFunction1() : innerFunction2();
}
1
2
3
4
5
6
7
8
9
不符合尾调用优化的例子
"use strict";

// 不符合:尾调用并没有返回
function outerFunction1 () {
innerFunction();
}

// 不符合:尾调用并没有直接返回
function outerFunction2 () {
const res = innerFunction();
return res;
}

// 不符合:尾调用之后还有额外的逻辑操作(.toString())
function outerFunction3 () {
return innerFunction().toString();
}

// 不符合:尾调用是闭包
function outerFunction4 () {
let name = “ienyh”;
return function () { return name; };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
总结 & Last
尾调用优化在递归场景下的效果是最明显的,因为递归代码容易在栈内存中迅速产生大量栈帧。
————————————————
作者:ienyh
原文链接:https://blog.csdn.net/qq_45265059/article/details/118896280

这篇关于Javascript尾调用优化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!