如何在不使用 eval() 的情况下,基于现有实例创建同类型的新实例

1次阅读

如何在不使用 eval() 的情况下,基于现有实例创建同类型的新实例

本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 constructor 属性调用构造函数,避免使用危险的 eval() 或依赖全局作用域的 window[name] 查找。

本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 constructor 属性调用构造函数,避免使用危险的 eval() 或依赖全局作用域的 window[name] 查找。

在 JavaScript 中,当你持有一个未知类型的实例(例如来自第三方库或运行时动态创建的对象),并希望生成一个同类型但独立的新实例时,最直观却高危的做法是拼接字符串 + eval()——这不仅存在严重的代码注入风险,还违反了 CSP(内容安全策略),且无法在严格模式或模块化环境中可靠运行。

✅ 正确且推荐的解决方案极其简洁:

const newInstanceOfSameclass = new sampleInstance.constructor();

sampleInstance.constructor 指向该实例原始的构造函数(即类本身),它是一个可调用的函数对象。因此,new sampleInstance.constructor() 等价于 new sampleClass_A()(以示例为例),无需任何字符串解析或全局查找。

下面是一个完整可运行的示例:

class SampleClassA {    name = "Archimedes";    constructor(age = 0) {      this.age = age;    }  }  class SampleClassB {    name = "Pythagoras";    constructor(score = 100) {      this.score = score;    }  }  const instanceA = new SampleClassA(28); const newInstanceA = new instanceA.constructor(); // ✅ 安全创建新实例 console.log(newInstanceA.name); // "Archimedes" console.log(newInstanceA.age);  // 0(使用默认参数)  // 同样适用于其他类 const instanceB = new SampleClassB(95); const newInstanceB = new instanceB.constructor(88); // ✅ 支持传参 console.log(newInstanceB.score); // 88

⚠️ 注意事项:

  • 构造函数必须支持无参(或提供默认值)调用:若目标类的构造函数强制要求参数(如 constructor(id) 且无默认值),直接调用 new inst.constructor() 会抛出错误。此时需额外维护参数信息,或改用工厂模式/反射式初始化。
  • 继承关系下仍有效子类实例的 constructor 指向其自身类(非父类),因此 new childInst.constructor() 会正确创建子类实例,符合预期。
  • 不适用于箭头函数或字面量对象:{}、Object.create(NULL) 或箭头函数没有 constructor 属性或其 constructor 不指向可实例化的函数,该方法仅适用于由 class 或普通函数构造器创建的实例。
  • ES Module 环境完全兼容:不依赖 window、globalThis 或模块命名空间,纯语言原生机制,适用于 Node.js、Deno、webpack/Vite 打包环境及浏览器。

? 总结:
new instance.constructor() 是语义清晰、性能优异、零依赖且安全可靠的替代方案。它充分利用了 JavaScript 原型链的设计本质,是处理“同类型实例克隆(非深拷贝)”场景的标准实践。请始终优先选用此方式,彻底摒弃 eval() 和 function() 构造器等危险动态执行手段。

text=ZqhQzanResources