JavaScript装饰器模式栈溢出问题:简化写法为何报错?
为什么修改后的装饰器写法会触发栈溢出?
这问题其实是函数引用覆盖后的无限递归导致的,咱们一步步拆解来看:
先看正确写法为什么没问题
第一种写法里,你用了一个立即执行函数来包裹逻辑:
instance.run = ((func) => { return function() { func(); console.log('decorator run'); } })(instance.run);
这里的关键是:立即执行函数执行的瞬间,instance.run还是原Dummy类的run方法,所以func变量保存的是原始方法的引用。当后续调用新的run方法时,func()调用的是最初的那个console.log('run'),完全不会触发递归,自然正常工作。
再看错误写法的问题所在
修改后的get函数里,你直接把instance.run替换成了新函数,但新函数内部又调用了instance.run():
function get() { let instance = new Dummy(); instance.run = function() { instance.run(); // 这里的instance.run已经是当前这个新函数了! console.log('decorator run'); } return instance; }
你要注意一个时序问题:当你完成instance.run = function() {...}这个赋值后,instance.run已经指向了这个新的匿名函数。所以当这个新函数执行时,里面的instance.run()其实是在调用它自己,而且没有任何终止条件,就会陷入无限递归——每调用一次就往调用栈里加一层,直到超过JS引擎的栈上限,就抛出了Maximum call stack size exceeded错误。
简单说:你没有保存原方法的引用,反而在新函数里反复调用已经被覆盖的自己,自然就栈溢出了。
内容的提问来源于stack exchange,提问作者Y Bond
相关产品推荐
相关产品推荐

