JavaScript 中的函数重新分配

Function reassignment in JavaScript

我有一个用 javascript 编写的函数,它跟踪传递给它的函数的递归调用。

function trace(fn){
    let indent = 0

    return function tracedFunction(args){
        console.log("| ".repeat(indent)+"|--"+fn.name,args)
        indent += 1
        let value = fn(args)
        console.log("| ".repeat(indent)+"|--"+"return",value)
        indent -= 1
        return value
    }

}

function fibo(num){
    if(num==0 || num==1)
        return 1;
    return fibo(num-1)+fibo(num-2);
}


fibo = trace(fibo)
fibo(4)

这给出了以下输出

|--fibo 4
| |--fibo 3
| | |--fibo 2
| | | |--fibo 1
| | | | |--return 1
| | | |--fibo 0
| | | | |--return 1
| | | |--return 2
| | |--fibo 1
| | | |--return 1
| | |--return 3
| |--fibo 2
| | |--fibo 1
| | | |--return 1
| | |--fibo 0
| | | |--return 1
| | |--return 2
| |--return 5
5

我的问题如下

  1. fibo = trace(fibo) 中发生了什么?

    • A 是重新定义 fibo 函数吗?
    • B 是否在全局范围内创建一个名为 fibo 的变量并将 trace(fibo) 分配给它?

    • 如果 (A) 是这种情况,那么这样做是一种好的做法吗?还有其他方法吗?

你在这里做的事情叫做"decorator"。这是 python 中非常常见和广泛使用的功能,但在 JS 中,经过大约 5 年的工作,它们仍在队列中。转译器和 TypeScript 确实支持装饰器,但仍然无法装饰一个函数,只能装饰一个方法,所以你必须将你的 fibo 包装在 class 中才能工作(如果你看起来很傻问我):

function trace(target, propertyKey, descriptor) {
    let indent = 0;
    let fn = target[propertyKey];

    descriptor.value = function tracedFunction(args){
       etc
     }
}

class Dummy {
    @trace
    static fibo(num) {
        if (num == 0 || num == 1)
            return 1;
        return Dummy.fibo(num - 1) + Dummy.fibo(num - 2);
    }
}

Dummy.fibo(4)

Typescript playground

在装饰器语法标准化并正确实现之前,装饰函数的唯一方法是如何编写它 - 应用装饰器并重新分配给原始名称。

为了回答您的问题,它是 A 和 B -- 函数在 javascript 中排在第一个 class,因此将一个函数值赋给一个变量会将该变量绑定到该函数和旧函数丢失了。函数声明语法 function foo() {...} 基本上只是 var foo = function .... 的快捷方式(一些讨厌的提升细节)。