如何修复Proxy中toString.caller调用报错:get caller method called on incompatible proxy
问题描述
请参考以下代码:
handler.toString = function() { return Reflect.get(original,'toString'); } handler.apply = scope.exportFunctionWithName(function(target, thisArgs, args){ try { return args.length? replacement.call(thisArgs, ...args): replacement.call(thisArgs); } catch (error){ try { return original.apply(thisArgs, args); } catch (error){ return target.apply(thisArgs, args); } } }, window, ""); const proxy = new window.Proxy(original, handler);
当调用ApiObj.toString()时,运行符合预期。但调用ApiObj.toString.caller时出现报错,错误信息如下:
get caller method called on incompatible proxy
修复方案
这个错误的核心原因是:你直接返回了原始的toString方法,而原生函数的caller属性对执行上下文有严格检查——当该方法在代理对象的上下文被访问时,会因代理与原始函数的上下文不匹配触发兼容性报错。
可以通过代理的get陷阱统一处理属性访问,确保方法的执行上下文与原始对象一致,修复代码如下:
const handler = { get(target, prop) { const value = Reflect.get(target, prop); // 对所有函数类型的属性,绑定原始对象作为执行上下文 if (typeof value === 'function') { return value.bind(target); } return value; }, apply(target, thisArgs, args) { try { return args.length ? replacement.call(thisArgs, ...args) : replacement.call(thisArgs); } catch (error) { try { return original.apply(thisArgs, args); } catch (error) { return target.apply(thisArgs, args); } } } }; const proxy = new window.Proxy(original, handler);
如果只想针对toString做单独处理,也可以用更精准的写法:
const handler = { get(target, prop) { if (prop === 'toString') { // 返回绑定了原始对象的toString方法,确保上下文一致 return original.toString.bind(original); } return Reflect.get(target, prop); }, apply(target, thisArgs, args) { try { return args.length ? replacement.call(thisArgs, ...args) : replacement.call(thisArgs); } catch (error) { try { return original.apply(thisArgs, args); } catch (error) { return target.apply(thisArgs, args); } } } }; const proxy = new window.Proxy(original, handler);
原理说明
- 直接给
handler赋值toString会跳过代理的get陷阱,导致返回的原始方法在代理上下文被访问时,caller属性的内部检查不通过。 - 通过
get陷阱返回绑定了原始对象的方法,能确保方法的执行上下文与原始对象完全一致,从而避免兼容性报错。 - 通用的函数绑定逻辑可以覆盖所有类似的方法属性,无需单独处理每个函数。
内容的提问来源于stack exchange,提问作者MD Luffy
相关产品推荐
相关产品推荐

