
本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 constructor 属性调用构造函数,避免 eval() 带来的安全风险与执行限制。
本文介绍一种安全、简洁且跨环境兼容的方式:直接通过实例的 `constructor` 属性调用构造函数,避免 `eval()` 带来的安全风险与执行限制。
在 JavaScript 中,当需要根据一个已有实例动态创建另一个同类型实例时,开发者有时会误入“反射式构造”的误区——例如先提取类名字符串,再拼接字符串并用 eval() 执行 new ClassName()。这种方式不仅存在严重的代码注入风险,还受限于运行环境(如非浏览器环境无 window 全局对象,window[className] 不可用),且破坏了静态分析与 TypeScript 类型检查能力。
✅ 正确且推荐的做法是:直接访问实例的 constructor 属性,并以函数形式调用它。
每个 JavaScript 实例都隐式继承自其构造函数的 prototype,而该实例的 constructor 属性(默认)指向其原始构造函数。因此,new sampleInstance.constructor() 即可安全、高效地创建一个全新实例,无需任何字符串解析或全局查找。
以下为完整示例:
class SampleClassA {
name = "Archimedes";
constructor(public id: number = Date.now()) {}
}
class SampleClassB {
name = "Pythagoras";
constructor(public version: string = "1.0") {}
}
const instanceA = new SampleClassA(42);
// ✅ 安全、通用、无需 eval
const newInstance = new instanceA.constructor(); // 类型推断为 SampleClassA
console.log(newInstance.name); // "Archimedes"
console.log(newInstance.id); // 新生成的时间戳(默认值)⚠️ 注意事项:
- 若构造函数接受必要参数(如上述 SampleClassA 的 id),new instance.constructor() 将使用其默认参数(若定义);如需传参,可显式传递:new instance.constructor(123)。
- 确保 constructor 属性未被手动覆盖(如 obj.constructor = null 或重写 prototype.constructor)。正常类声明下该属性可靠。
- 对于使用 Object.create(null) 创建的对象或某些 Proxy 包装对象,constructor 可能不可靠,此时需结合业务逻辑兜底(如白名单校验或显式类型标记)。
- TypeScript 中,该方式仍支持类型推导(配合 as const 或泛型约束可进一步强化类型安全)。
? 总结:new obj.constructor() 是原生、轻量、环境无关的标准方案,兼具安全性、可读性与性能优势。它应作为替代 eval() 动态构造的首选实践,也是理解 JavaScript 原型机制的典型应用。










