Comments (30)
如下场景:
// 尾调用
function f(x){
return g(x);
}
在chrome中跑了下,那个控制台 -> Sources -> Call Stack中观察到,f(x) 和g(x)都在stack中,并没有出现如下这种情况啊
// 伪代码
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.push(<g> functionContext);
ECStack.pop();
from blog.
@cikeyin 这不是尾递归,这是闭包.朋友,基础很重要啊!!!
from blog.
终于明白了尾递归,没白来
from blog.
@mqyqingfeng 如果真的能够写一个算法系列,那真是大大的好啊!
from blog.
关于尾调用刚开始还以为作者说错了 所以又仔细看了看阮老师的http://es6.ruanyifeng.com/#docs/function#%E5%B0%BE%E8%B0%83%E7%94%A8%E4%BC%98%E5%8C%96
还有尾调用优化的问题 是否跟是否使用严格模式有关系
from blog.
function f(x){ return g(x); } // 非尾调用 function f(x){ return g(x) + 1; }谁能帮我解释下这俩的执行上下文栈有啥区别么
@tancgo 可以看下这个文章开头部分的解释
https://es6.ruanyifeng.com/#docs/function#%E5%B0%BE%E8%B0%83%E7%94%A8%E4%BC%98%E5%8C%96
函数调用会产生调用栈 call stack,用于保存函数调用的一些信息,比如局部变量等。非尾调用g(x) + 1,需要留存住这个 + 1,但是尾调用g(x),不需要保留任何信息,直接用当前call stack 取代之前call stack 节省了空间。言语很拙劣,不知道讲清楚了没,😂。
from blog.
阶乘函数优化那节,factorial中的factorial多打了个2,newFactorial(5) // 24这个也手误了,newFactorial函数用的也不是你链接中的curry,而是partial
from blog.
@SilenceZeng 非常感谢指出~ 已经修改,以后写文章的时候会更加严谨一些~
from blog.
@coderLius 怎么观察的,我怎么看不到?
from blog.
@coderLius 很抱歉之前没有看到这个问题,V8 并没有部署尾递归优化,所以其实从 Call Stack 中看不到期望的效果
from blog.
@jasonzhangdong 在这里
from blog.
看了你这张截图,然后试着把数据跑出来,看着数据的变化,感觉更能理解这儿的this,执行上下文了。
然后我的第一反应是,在js深入讲解的时候,你应该就把截图操作的放上去做下举例;第二反应是,涨姿势了,然后希望你能更多的简单讲解下(甚至只是一张截图),这些工具在你们手上是怎么发挥作用的。
from blog.
@qujsh 感谢建议~ 以后可以写一个工具系列~ 哈哈
from blog.
@hazxy 算法系列真是任重而道远呐~
from blog.
执行上下文栈和函数调用栈是一个东西吧
from blog.
@mqyqingfeng V8 并没有部署尾递归优化
那就是说,尾递归能否对性能有改进,取决于运行的平台、环境咯?那么是否会存在一些平台反而是常规的递归性能比尾递归更好呢?
function factorial(n, res) {
if (n == 1) return res;
return factorial(n - 1, n * res)
}
function factorial2(n) {
if (n == 1) return n;
return n * factorial(n - 1)
}
console.time('尾递归');
factorial(10000, 1)
console.timeEnd('尾递归');
console.time('正常递归');
factorial2(10000)
console.timeEnd('正常递归');
在chrome下,尾递归的性能通常较好,偶尔性能劣于正常的递归;
在safari和firefox下,尾递归的性能通常较差,甚至在firefox下经常出现4、5倍的耗时差距;
from blog.
@Tan90Qian 代码写错了哈……
function factorial(n, res) {
if (n == 1) return res;
return factorial(n - 1, n * res)
}
function factorial2(n) {
if (n == 1) return n;
// 这里应该是 factorial2
return n * factorial2(n - 1)
}
console.time('尾递归');
factorial(10000, 1)
console.timeEnd('尾递归');
console.time('正常递归');
factorial2(10000)
console.timeEnd('正常递归');
from blog.
@mqyqingfeng 你好!有个疑问:你在《JavaScript深入之执行上下文栈》 中举的这个例子不也是尾调用吗?为什么执行上下文栈的变化和本章的尾调用不同?
from blog.
@cikeyin 按照我的理解,这两个地方执行栈都没问题。一个是没有用尾调优化的栈,一个是使用了尾调用优化的栈(现在实际在chrome下跑也暂时还看不到尾调用优化的结果)。可能之前博主在写执行上下文栈的时候更多的重心是在执行上下文栈这块,现在写递归就顺带写了执行栈的优化。
from blog.
以前看阮一峰老师的ES6,看到尾调用这边云里雾里,后来看了冴羽大神写的执行环境栈运行原理,回过头看尾调用终于看懂了。
尾调用就是保证每次执行的时候,ECS里面只有一个函数执行上下文,这样在递归时候不会栈溢出。
from blog.
function f(x){ return g(x) + 1; }
我想问下为啥return g(x)和return g(x)+1,前者的执行上下文栈会先push再pop,后者就不会?
from blog.
尾递归学习总结:
// 求和
function sum(n, res = 0) {
if (n < 1) return res;
return sum(n - 1, n + res);
}
sum(5); // 15
// 斐波拉契数
function fibonacci(n, sum1 = 1, sum2 = 1) {
if (n <= 2) return sum2;
return fibonacci(n - 1, sum2, sum1 + sum2);
}
fibonacci(5); // 5
// 阶乘
function factorial(n, res = 1) {
if (n <= 1) return res;
return factorial(n - 1, n * res);
}
from blog.
function f(x){ return g(x) + 1; }
我想问下为啥return g(x)和return g(x)+1,前者的执行上下文栈会先push再pop,后者就不会?
ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。博主讲的应该是在严格模式下
from blog.
function f(x){ return g(x) + 1; }
我想问下为啥return g(x)和return g(x)+1,前者的执行上下文栈会先push再pop,后者就不会?
return g(x) 的时候 f(x)已经结束了,所以f(x)push之后就pop了
return g(x)+1的时候. 因为return会返回计算结果. 所以先g(x)调用的返回值与1相加.那么就是f(x)push之后g(x)push紧接着g(x)调用完pop 再返回最终结果. f(x)也pop
from blog.
function f(x){
return g(x);
}
// 非尾调用
function f(x){
return g(x) + 1;
}
谁能帮我解释下这俩的执行上下文栈有啥区别么
from blog.
@tancgo 我理解的出入栈如下:
// 尾调用
function f(x){
return g(x);
}
ECS:[] -> gloabalContext入栈 -> fContext入栈 -> fContext出栈 -> gContext入栈 -> gContext出栈
// 非尾调用
function f(x){
return g(x) + 1;
}
ECS:[] -> gloabalContext入栈 -> fContext入栈 -> gContext入栈 -> gContext出栈 -> fContext出栈
from blog.
function f(x){ return g(x); } // 非尾调用 function f(x){ return g(x) + 1; }谁能帮我解释下这俩的执行上下文栈有啥区别么
@tancgo 可以看下这个文章开头部分的解释
https://es6.ruanyifeng.com/#docs/function#%E5%B0%BE%E8%B0%83%E7%94%A8%E4%BC%98%E5%8C%96
from blog.
关于尾递归,推荐一下文章:https://site.douban.com/196781/widget/notes/12161495/note/262014367/ 虽然有点老...
另外,文章中《数据结构与算法分析:C描述》中的尾递归的介绍在 3.3.3章节的最后(我这边的版本是 P61 )
from blog.
个人感觉递归最重要的一点是,函数的名字要具有语义化
from blog.
补充几个小点,可能更加容易理解:
1、尾调用的概念:某个函数的 最后一步是调用另外一个函数,即成为尾调用。
2、尾调用优化: 当函数最后一步调用另外一个函数(fn1)时,函数(fn1)内部么没有对父层函数的的任何变量有所依赖,或者说所有的依赖的计算都是在父函数中完成的,这时执行这个函数(fn1)时,父函数的执行上下文会被从栈内弹出,从而实现栈内只有 函数(fn1)的执行上下文,
*按照我的理解,只有进行了尾调用优化的尾调用才算是有实践意义的 ‘尾调用’;
举例说明:
1、没有进行尾调用
大佬文章的函数执行上下文栈中的例子
在这个例子中函数最后一步的确是调用 另外一个函数,从概念意义上讲,它是一个尾调用,但是由于调用的这个函数仍然依赖父层函数的变量scope ,所有并不会进行尾调用优化,所以它并不能称之为 有实践意义的 ‘尾调用’(可以理解为就是大佬文中所描述的那样的出入栈规则,)
另外 有些浏览器不支持尾调用优化,如chrome
from blog.
Related Issues (20)
- 冴羽答读者问:如何在工作中打造影响力,带动同事?
- 无
- 冴羽答读者问:如何学习更有计划性、提升更稳更快? HOT 4
- 冴羽答读者问:过程比结果重要吗? HOT 1
- 冴羽答读者问:冴羽,你为什么写起了鸡汤? HOT 3
- 聊聊 npm 的语义化版本(Semver) HOT 4
- How to create Backlinks 😤
- 思考题第2题
- 可以理解为原型是prototype,原型链是通过__proto__ 链接起来的吗
- React 之 createElement 源码解读 HOT 8
- React 之元素与组件的区别 HOT 1
- React 之 Refs 的使用和 forwardRef 的源码解读
- React 之 Context 的变迁与背后实现 HOT 1
- 第一段不报错啊,刚试过了,会打印1
- how can i HOT 1
- Hosting of Blog Issue
- 全局对象
- 为啥每次都要创建一个 Child函数来new 子类?现在不都是 const p1 = new Person(); const p2 = new Person()吗
- 文档内容中文件结构的错位 HOT 1
- 原型链继承
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from blog.