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

为何Coffeescript中C访问B的静态属性为undefined而A访问正常?

为什么循环依赖下类B的静态属性在C中访问是undefined,而在a中是1?

代码示例

a.coffee

B = require './b'
C = require './c'
console.log B.someStaticVar
C.checkB()

b.coffee

C = require './c'
class B
  @someStaticVar: 1
module.exports = B;

c.coffee

B = require './b'
class C
  @checkB: ->
    console.log B.someStaticVar
module.exports = C

执行结果

执行coffee a.coffee后输出:

$ coffee a.coffee
1
undefined

问题原因:循环模块依赖的加载顺序问题

这本质是Node.js(CoffeeScript编译后运行在Node环境)的模块循环加载机制导致的,咱们一步步拆解加载执行的全过程:

  1. 启动a.coffee,Node开始加载模块a:
    • 第一步加载./b,进入b的模块执行流程。
  2. 加载b模块时,首先执行C = require './c',转而加载c模块:
    • 在c模块里,第一行是B = require './b'——这时候b模块还没执行完(它刚触发了c的加载,还没到定义class B和赋值module.exports = B的步骤)。
    • Node的模块加载规则是:如果请求加载的模块正在加载中,就直接返回该模块当前的module.exports值。此时b的module.exports还是默认的空对象(因为还没被赋值),所以c里的B变量就指向这个空对象。
    • 接着c模块完成剩余代码:定义C类,把C赋值给module.exports,然后c加载完成,回到b模块的执行。
  3. 回到b模块,继续执行剩余代码:定义class B(并设置静态属性someStaticVar:1),然后把B赋值给b的module.exports——这一步是把b模块的导出引用从原来的空对象换成了B类,但**c模块里的B变量依然指向之前的那个空对象**,不会自动更新。
  4. 回到a模块,b加载完成,a里的B变量指向的是完整的B类,所以console.log B.someStaticVar输出1。
  5. 然后a加载./c,因为c已经加载过了,直接取缓存里的C类。调用C.checkB()时,C类里的checkB方法访问的是c模块里的那个B变量——也就是之前的空对象,自然没有someStaticVar属性,所以输出undefined。

修复方案

你可以调整模块的依赖结构避免循环依赖,或者延迟对依赖模块的访问:

比如修改c.coffee,不在模块顶部加载B,而是在checkB方法内部动态获取:

class C
  @checkB: ->
    B = require './b'
    console.log B.someStaticVar
module.exports = C

这样每次调用checkB时,都会获取b模块最终导出的B类,就能正确拿到someStaticVar的值了。

内容的提问来源于stack exchange,提问作者BobJoe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:18:42