调用栈的英文名叫作Call Stack,你们或多或少是有听过的,可是对于js调用栈的工做方式以及如何在工做中利用这一特性,大部分人可能没有进行过更深刻的研究,这块内容能够说对咱们前端来讲就是所谓的基础知识,咋一看好像用处并无很大,但掌握好这个知识点,就可让咱们在之后能够走的更远,走的更快!javascript
栈是一种听从后进先出(LIFO
)原则的有序集合,新元素都靠近栈顶,旧元素都接近栈底。前端
生活中的栗子,帮助一下理解:java
餐厅里面堆放的盘子(栈),一开始放的都在下面(先进),后面放的都在上面(后进),洗盘子的时候先从上面开始洗(先出)。git
机制:es6
程序运行到一个函数,它就会将其添加到调用栈中,当从这个函数返回的时候,就会将这个函数从调用栈中删掉。github
看一下例子帮助理解:web
// 调用栈中的执行步骤用数字表示
printSquare(5); // 1 添加
function printSquare(x) {
var s = multiply(x, x); // 2 添加 => 3 运行完成,内部没有再调用其余函数,删掉
console.log(s); // 4 添加 => 5 删掉
// 运行完成 删掉printSquare
}
function multiply(x, y) {
return x * y;
}
复制代码
调用栈中的执行步骤以下(删除multiply的步骤被省略了):segmentfault
调用侦:浏览器
每一个进入到调用栈中的函数,都会分配到一个单独的栈空间,称为“调用侦”。
在调用栈中每一个“调用侦”都对应一个函数,最上方的调用帧称为“当前帧”,调用栈是由全部的调用侦造成的。
找到一张图片,调用侦:
调用栈的内存消耗:
如上图,函数的变量等信息会被调用侦保存起来,因此调用侦中的变量不会被垃圾收集器回收。
当函数嵌套的层级比较深了,调用栈中的调用侦比较多的时候,这些信息对内存消耗是很是大的。
针对这种状况除了咱们要尽可能避免函数层级嵌套的比较深以外,ES6提供了“尾调用优化”来解决调用侦过多,引发的内存消耗过大的问题。
何谓尾调用:
尾调用指的是:函数的最后一步是调用另外一个函数。
function f(x){
return g(x); // 最后一步调用另外一个函数而且使用return
}
function f(x){
g(x); // 没有return 不算尾调用 由于不知道后面还有没有操做
// return undefined; // 隐式的return
}
复制代码
尾调用优化优化了什么?
尾调用用来删除外层无用的调用侦,只保留内层函数的调用侦,来节省浏览器的内存。
下面这个例子调用栈中的调用侦一直只有一项,若是不使用尾调用的话会出现三个调用侦:
a() // 1 添加a到调用栈
function a(){
return b(); // 在调用栈中删除a 添加b
}
function b(){
return c() // 删除b 添加c
}
复制代码
防止爆栈:
浏览器对调用栈都有大小限制,在ES6以前递归比较深的话,很容易出现“爆栈”问题(stack overflow)。
如今可使用“尾调用优化”来写一个“尾递归”,只保存一个调用侦,来防止爆栈问题。
注意:
若是要使用外层函数的变量,能够经过参数的形式传到内层函数中
function a(){
var aa = 1;
let b = val => aa + val // 使用了外层函数的参数aa
return b(2) // 没法进行尾调用优化
}
复制代码
更多:
关于尾递归以及更多尾调用优化的内容,推荐查阅ES6入门-阮一峰
查看调用栈有什么用
查看函数的调用顺序是否跟预期一致,好比不一样判断调用不一样函数。
快速定位问题/修改三方库的代码。
当接手一个历史项目,或者引用第三方库出现问题的时候,能够先查看对应API的调用栈,找到其中涉及的关键函数,针对性的修复它。
经过查看调用栈的形式,帮助我快速定位问题,修改三方库的源码。
如何查看调用栈
console.trace
a()
function a() {
b();
}
function b() {
c()
}
function c() {
let aa = 1;
console.trace()
}
复制代码
如图所示,点击右侧还能查看代码位置:
bugger
打断点形式,这也是我最喜欢的调试方式:平时须要有意识的去作这种小的优化(我如今就是),尽可能写最佳实践的代码。
项目小的时候可能没什么影响,当一个项目体量大的时候,尤为是一些小方法拼接嵌套成一个大的API输出时,这时调用栈中对内存的消耗将是巨大的!这种优化也是不可小觑的,积跬步以致千里,诸君共勉!
本文主要讲了这几个方面的内容:
最后:以前写过一篇关于垃圾回收机制与内存泄露的文章,感兴趣的同窗能够扩展一下。
以上2019/5/19
参考资料: