从字符串转换的对象创建函数时出现createPromise未定义错误求助
ReferenceError: createPromise is not defined 问题 你的问题出在使用 new Function() 创建函数时的作用域限制上,我来帮你拆解一下原因和解决办法:
错误原因
new Function(argList, body) 创建的函数是运行在全局作用域中的,而非你当前模块的作用域。这意味着这些解析出来的函数无法访问模块内部定义的 createPromise(或其他模块级变量),当函数执行时自然会抛出“未定义”的错误。
本质上,new Function 是从全局作用域查找变量的,而你的 createPromise 大概率是在模块内部(比如某个类或私有函数里)定义的,不在全局作用域中,所以函数找不到它。
解决方案
方案1:避免序列化函数(推荐)
JSON 本身并不支持序列化函数,这属于非常规用法。更可靠的做法是只序列化对象的数据部分,恢复时重新绑定方法:
比如,假设你的 kc 对象是一个包含数据和方法的实例,存储时只存数据:
// 存储时:仅保留数据属性,剔除方法 localStorage.setItem('kc', JSON.stringify({ token: kc.token, expires: kc.expires, // 其他需要存储的业务数据... }));
恢复时,重新创建 kc 实例并赋值数据:
const transToObj = () => { const data = JSON.parse(localStorage.getItem('kc')); // 假设你有一个KC类/构造函数用于创建实例 const kc = new KC(); // 将存储的数据赋值给实例 Object.assign(kc, data); return kc; };
这样 kc 的方法(比如 updateToken)会带着正确的作用域,自然能访问到 createPromise 这类依赖。
方案2:用 eval 替代 new Function(仅限可信场景)
如果你必须从字符串恢复函数,可以使用 eval(注意:仅当你能完全信任这个字符串的来源时才用,避免XSS风险)。eval 创建的函数会继承当前模块的作用域,能直接访问到 createPromise:
修改你的 transToObj 函数:
export const transToObj = strObj => JSON.parse(strObj, (key, val) => { if (typeof val === 'string' && val.indexOf('function') === 0) { // 用eval解析函数,继承当前模块作用域 return eval(`(${val})`); } return val; });
方案3:将依赖挂载到全局(不推荐)
如果 createPromise 可以被挂载到全局作用域(比如 window.createPromise),那 new Function 创建的函数就能找到它,但这种做法会污染全局作用域,仅作为临时 workaround:
// 在模块内将createPromise挂载到window window.createPromise = createPromise;
代码修改示例(方案2)
调整后的完整代码如下:
export const transToObj = strObj => JSON.parse(strObj, (key, val) => { if (typeof val === 'string' && val.indexOf('function') === 0) { // 用eval解析函数,继承当前作用域 return eval(`(${val})`); } return val; }); const refreshToken = () => { const kc = transToObj(localStorage.getItem('kc')); kc.updateToken(30).success().error(() => { window.location.reload(true); }); }; // eslint-disable-next-line no-return-await const getNewToken = async () => await refreshToken();
内容的提问来源于stack exchange,提问作者Mohammad Fared

