代码之家  ›  专栏  ›  技术社区  ›  David542

使用WeakMap跟踪函数调用

  •  0
  • David542  · 技术社区  · 2 年前

    为了学习使用 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 然后回到 添加 。此外,以上是Weakmap的合法使用吗?

    1 回复  |  直到 2 年前
        1
  •  1
  •   CertainPerformance    2 年前

    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);

    此外,以上是Weakmap的合法使用吗?

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

    也就是说,这当然是WeakMap的合法使用 在地图上 ,因为它允许函数(及其调用计数)在没有其他东西可以引用它时被垃圾收集。

    我想另一个选项是将返回的函数作为放入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