在很多时候,递归算法能够解决很多问题,但是在以前它是一种以空间换取性能的办法,如果改成循环,往往理解起来会很困难,Javascript基于此进行了一种尾调用的优化,在满足如下条件时,会激活尾调用:
1. 返回一个函数自调用
2.传给递归函数的参数没有形成闭包;
判断一个递归函数能否进行尾调用优化的最快方法:
增加一个默认参数,看看能否用它来代表最终的结果 - holder
优化前调用步骤:
● 计算实参表达式。
● 创建一个足以容纳函数所有形参和变量大小的新活跃对象(activationobject)。
● 将当前正在调用的函数引用存入新活跃对象。
● 将实参存入新活跃对象的实参列表,缺失的实参会被定义为undefined,而多余的实参则会被忽略。
● 将所有的变量都以undefined存入新活跃对象。
● 将新活跃对象中的next instruction field设置为函数执行完毕后需要立即执行的指令。
● 将当前活跃对象存入新活跃对象中的caller字段,要知道调用栈在JavaScript中只是一个概念,它实际上是活跃对象的链表。
● 将新活跃对象设为“当前活跃对象”。
● 开始执行被调用函数。
优化后:
● 计算实参表达式。如果当前活跃对象足够大,
则:● 直接把当前活跃对象设为新活跃对象。 --- 一般都到这里了,除非将之前的函数作用域加了引用形成闭包;
否则:● 创建一个足以容纳函数所有形参和变量大小的新活跃对象;● 将当前活跃对象的caller字段直接赋值给新活跃对象;● 直接将新活跃对象设置为“当前活跃对象”。● 将当前正在调用的函数引用存入新活跃对象。● 将实参存入新活跃对象的实参列表,缺失的实参会被定义为undefined,而多余的实参则会被忽略。● 将所有的变量都以undefined存入新活跃对象。● 开始执行被调用函数。
可以说js引擎对于算法的优化还是很关注的,比较越来越卷了
网友评论