You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript装饰器中函数表达式与函数声明的行为差异问题

函数创建方式导致装饰器计数器共享的原因分析

问题的核心差异在于变量作用域与声明方式:

1. 未声明的函数表达式导致全局变量污染

第一个代码中,wrapper = function(...args)没有使用var/let/const声明变量,这会让wrapper自动成为全局变量(浏览器环境挂载到window,Node.js环境挂载到global)。

执行流程拆解:

  • 第一次调用counter(sum):
    全局变量wrapper被赋值为第一个包装函数,同时给它添加counter = 0属性,最后将这个函数返回赋值给a。
  • 第二次调用counter(mul):
    全局变量wrapper被重新赋值为第二个包装函数,同时重置它的counter = 0,返回后赋值给b。
  • 调用a()或b()时:
    函数内部的wrapper.counter++实际操作的是全局的wrapper变量(也就是最后一次赋值给b的那个函数)。而a指向的第一个包装函数的counter属性从未被修改过,始终是初始的0;所有调用次数都累加给了b对应的全局wrapper,最终出现a.counter=0、b.counter=4的结果。

2. 函数声明的局部作用域隔离

第二个代码中,function wrapper(...args)是函数声明,它会被绑定在counter函数的局部作用域内:

  • 每次调用counter都会创建一个独立的局部作用域,每个作用域内的wrapper都是全新的函数实例。
  • 每个wrapper的counter属性都是独立的,分别属于a和b指向的包装函数,因此调用次数会正确统计,不会互相干扰。

修正方案(函数表达式的正确写法)

如果要使用函数表达式,只需给wrapper添加局部变量声明即可,避免全局污染:

function counter(func) {
    // 使用let声明局部变量wrapper
    let wrapper = function(...args) {
        wrapper.counter++;
        let result = func.apply(null, args);
        return result;
    }
    wrapper.counter = 0;
    return wrapper;
}

内容的提问来源于stack exchange,提问作者Иван Бельков

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 12:55:18