使用 Wea​​kMap 跟踪函数调用

Using a WeakMap to track function invocations

为了学习如何使用 WeakMap,我想出了以下示例来跟踪函数调用:

var map = new WeakMap();

function countFunctionInvocations(func) {
    return function(...args) {
        map.set(func, (map.get(func) || 0)+1);
        return func.apply(this, args);
    }
};


const _add = (x,y) => x+y;
const _inc = x     => x+1;


const add = countFunctionInvocations(_add);
const inc = countFunctionInvocations(_inc);

add(2,3);
add(1,2);
add(2,3);
add(2,3);
inc(inc(1));
console.log(map.get(_add), map.get(_inc));
// 4 2

什么是更简洁的实现方式,因为我必须来回为函数添加别名,例如从 add_add 再回到 add。另外,以上是 Weakmap 的合法用法吗?

WeakMap 的使用非常奇怪 - 正如您所注意到的,如果您想通过函数查找它,您必须将这些函数存储在变量中,这些变量与 count-invokified 功能。这让事情变得很尴尬,而且 WeakMap 似乎没有比普通对象有净收益,只要你没有函数名称冲突。

如果您正在寻找的内容允许这样做,您可以将另一个参数传递给 countFunctionInvocations 以指示名称,从而允许您传递(简洁、匿名)箭头函数。

const counts = {};

function countFunctionInvocations(name, func) {
    return function(...args) {
        counts[name] = (counts[name] ?? 0) + 1;
        console.log("called", name, counts[name]);
        return func.apply(this, args);
    }
};

const add = countFunctionInvocations('add', (x,y) => x+y);
const inc = countFunctionInvocations('inc', x => x + 1);

add(2,3);
add(1,2);
add(2,3);
add(2,3);
inc(inc(1));
console.log(counts.add, counts.inc);

Additionally, is the above a legitimate usage of Weakmap?

我的意思是,它可以被使用,但正如我们所注意到的那样 - 必须对一个函数有两个单独的引用是很尴尬的 - 一个是基本函数,一个是由 countFunctionInvocations.

也就是说,这肯定是 WeakMap 在 Map 上的合法用法,因为它允许函数(及其调用计数)在没有其他内容可以引用时被垃圾收集它。

我想另一种选择是将返回的函数放入 Map 中,这样您在外部只有一个标识符,但它需要一个 function 或第二个参数表示函数名,否则countFunctionInvocations里面只能看到一个没有名字的匿名函数。

const map = new WeakMap();

function countFunctionInvocations(func) {
    const fn = (...args) => {
        map.set(fn, (map.get(fn) || 0) + 1); // use returned function in Map
        return func.apply(this, args); // invoke passed function
    }
    return fn;
};

const add = countFunctionInvocations(function add(x, y) { return x + y });
const inc = countFunctionInvocations(function inc(x) { return x + 1 });

add(2,3);
add(1,2);
add(2,3);
add(2,3);
inc(inc(1));
console.log(map.get(add), map.get(inc));
// 4 2