5
经过一些resent测试后,我发现我的实现不能处理非常多的递归。尽管在Firefox中进行了一些测试后,我发现这可能比我原先想象的更普遍。我相信基本的问题是我的实现需要3次调用才能进行函数调用。第一次调用是一个名为Call
的方法,它确保调用正在对可调用对象进行调用,并获取任何引用参数的值。第二次调用是在ICallable
接口中定义的名为Call
的方法。此方法创建新的执行上下文,并在未创建的情况下构建lambda表达式。最后的调用是对函数对象封装的lambda进行的。清楚地做一个函数调用是相当繁重的,但我相信只要稍微调整一下,我就可以在使用这个实现时使递归成为可行的工具。我该如何改进ECMAScript实现的递归功能?
public static object Call(ExecutionContext context, object value, object[] args)
{
var func = Reference.GetValue(value) as ICallable;
if (func == null)
{
throw new TypeException();
}
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
args[i] = Reference.GetValue(args[i]);
}
}
var reference = value as Reference;
if (reference != null)
{
if (reference.IsProperty)
{
return func.Call(reference.Value, args);
}
else
{
return func.Call(((EnviromentRecord)reference.Value).ImplicitThisValue(), args);
}
}
return func.Call(Undefined.Value, args);
}
public object Call(object thisObject, object[] arguments)
{
var lexicalEnviroment = Scope.NewDeclarativeEnviroment();
var variableEnviroment = Scope.NewDeclarativeEnviroment();
var thisBinding = thisObject ?? Engine.GlobalEnviroment.GlobalObject;
var newContext = new ExecutionContext(Engine, lexicalEnviroment, variableEnviroment, thisBinding);
Engine.EnterContext(newContext);
var result = Function.Value(newContext, arguments);
Engine.LeaveContext();
return result;
}
我想转换尾循环到循环现在不在范围之内?这样你可以避免完全调用。 – 2010-05-23 22:13:10
@DJJJJSJP - 我始终坚持在我脑海中使用尾递归的想法,但我也在寻找如何使调用本身不那么沉重以提高性能的建议。另外,我不认为在函数的复杂性太大的情况下,尾递归可以正确实现。 – ChaosPandion 2010-05-23 22:34:47
好吧,它看起来并没有做任何不必要的事情,你有没有试过用探查器来运行它?我的意思是,函数调用(在释放模式下)在CLR中并不是非常昂贵(不幸的是,第二个调用有点太不能被JIT内联),所以我怀疑这就是为什么它很重。也许在Reference.GetValue()什么的?分析器肯定会非常有帮助。 – 2010-05-23 23:11:44