1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

edit function/tail call

This commit is contained in:
Ruan Yifeng 2015-04-10 11:07:21 +08:00
parent 19652900c9
commit aba2df6647

View File

@ -237,15 +237,15 @@ rest参数中的变量代表一个数组所以数组特有的方法都可以
```javascript
function push(array, ...items) {
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
push(a, 1, 2, 3)
```
@ -703,9 +703,9 @@ function f(x) {
尾调用之所以与其他调用不同,就在于它的特殊的调用位置。
我们知道,函数调用会在内存形成一个“调用栈”call stack保存调用位置和内部变量等信息。如果在函数A的内部调用函数B就会在A的调用栈上方再形成一个B的调用栈。等到B运行结束将结果返回到AB的调用栈才会消失。如果函数B内部还调用函数C那就还有一个C的调用栈以此类推。
我们知道,函数调用会在内存形成一个“调用记录”又称“调用帧”call frame保存调用位置和内部变量等信息。如果在函数A的内部调用函数B那么在A的调用记录上方还会形成一个B的调用记录。等到B运行结束将结果返回到AB的调用记录才会消失。如果函数B内部还调用函数C那就还有一个C的调用记录栈,以此类推。所有的调用记录就形成一个“调用栈”call stack
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用栈,取代外层函数的调用栈就可以了。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。
```javascript
function f(x) {
@ -723,15 +723,15 @@ function f(x) {
g(3);
```
上面代码中如果函数g不是尾调用函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后函数f就结束了所以执行到最后一步完全可以删除 f(x) 的调用栈,只保留 g(3) 的调用栈
上面代码中如果函数g不是尾调用函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后函数f就结束了所以执行到最后一步完全可以删除 f(x) 的调用记录,只保留 g(3) 的调用记录
这就叫做“尾调用优化”Tail call optimization即只保留内层函数的调用栈。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用栈只有一项,这将大大节省内存。这就是“尾调用优化”的意义。
这就叫做“尾调用优化”Tail call optimization即只保留内层函数的调用记录。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是“尾调用优化”的意义。
### 尾递归
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
递归非常耗费内存,因为需要同时保存成千上百个调用很容易发生“栈溢出”错误stack overflow。但对于尾递归来说由于只存在一个调用,所以永远不会发生“栈溢出”错误。
递归非常耗费内存,因为需要同时保存成千上百个调用记录很容易发生“栈溢出”错误stack overflow。但对于尾递归来说由于只存在一个调用记录,所以永远不会发生“栈溢出”错误。
```javascript
function factorial(n) {
@ -742,9 +742,9 @@ function factorial(n) {
factorial(5) // 120
```
上面代码是一个阶乘函数计算n的阶乘最多需要保存n个调用,复杂度 O(n) 。
上面代码是一个阶乘函数计算n的阶乘最多需要保存n个调用记录,复杂度 O(n) 。
如果改写成尾递归,只保留一个调用,复杂度 O(1) 。
如果改写成尾递归,只保留一个调用记录,复杂度 O(1) 。
```javascript
function factorial(n, total) {