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

1次阅读

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

本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 constructor 属性调用构造函数,避免 eval() 带来的安全风险与执行上下文限制。

本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 `constructor` 属性调用构造函数,避免 `eval()` 带来的安全风险与执行上下文限制。

在 JavaScript 开发中,有时需要根据一个已知实例动态创建同一类的另一个新实例(例如在序列化/反序列化、克隆逻辑或插件系统中)。常见误区是通过 instance.constructor.name 拼接字符串再用 eval() 执行构造调用——这不仅存在严重安全漏洞(如代码注入),还受限于运行环境(如非浏览器环境无 window 全局对象,window[className] 不可用)。

✅ 正确做法非常简单:直接访问实例的 constructor 属性并调用它。该属性指向原始构造函数本身,是标准、可靠且环境无关的引用。

以下为完整示例:

class SampleClassA {    name = "Archimedes";    constructor(age = 25) {     this.age = age;   } }  class SampleClassB {    name = "Pythagoras";    constructor(level = "senior") {     this.level = level;   } }  const sampleInstance = new SampleClassA(30);  // ✅ 安全、推荐:直接使用 constructor 属性 const newInstance = new sampleInstance.constructor(); // 使用默认参数 console.log(newInstance.name); // "Archimedes" console.log(newInstance.age);  // 25(构造函数默认值)  // ✅ 支持传参:可传递任意合法构造参数 const newInstanceWithArgs = new sampleInstance.constructor(42); console.log(newInstanceWithArgs.age); // 42

⚠️ 注意事项:

  • 构造函数需支持无参调用:若目标类的构造函数强制要求参数(如无默认值的必填参数),直接 new instance.constructor() 会抛出错误。此时应结合业务逻辑预设合理默认值,或封装工厂方法统一处理。
  • 继承场景下仍有效:instance.constructor 在子类实例中准确返回其实际构造函数(而非父类),因此该方式天然支持继承链。
  • 不适用于箭头函数或无构造器对象:constructor 属性仅对由 class 或 function 构造的对象有效;纯对象字面量(如 {})或 Object.create(NULL) 实例无 constructor,需额外判空。
  • typescript 用户注意:此方案完全兼容 TypeScript,无需类型断言;如需更强类型保障,可配合泛型工具类型(如 InstanceType)进行静态检查。

总结:new instance.constructor(…args) 是替代 eval() 动态实例化的标准实践——零依赖、零安全风险、全环境兼容(Node.js / 浏览器 / Deno / Web Workers),应作为首选方案写入团队编码规范。

text=ZqhQzanResources