Reflect.construct()

Baseline 已广泛支持

此特性已非常成熟,可在多种设备和浏览器版本上使用。自 ⁨2016 年 9 月⁩以来,它已在各大浏览器中可用。

Reflect.construct() 静态方法类似于 new 运算符,但以函数的形式存在。它等同于调用 new target(...args)。它还允许指定不同的 new.target 值。

试一试

function func1(a, b, c) {
  this.sum = a + b + c;
}

const args = [1, 2, 3];
const object1 = new func1(...args);
const object2 = Reflect.construct(func1, args);

console.log(object2.sum);
// Expected output: 6

console.log(object1.sum);
// Expected output: 6

语法

js
Reflect.construct(target, argumentsList)
Reflect.construct(target, argumentsList, newTarget)

参数

目标

要调用的目标函数。

argumentsList

一个 类数组对象,指定了应使用哪些参数调用 target

newTarget 可选

targetnew.target 表达式的值。默认为 target。通常(参见示例),target 指定初始化对象的逻辑,而 newTarget.prototype 指定构造对象的原型

返回值

target(或 newTarget,如果存在)的新实例,由 target 作为构造函数使用给定的 argumentsList 初始化。

异常

TypeError

如果 targetnewTarget 不是构造函数,或者 argumentsList 不是对象,则会抛出该错误。

描述

Reflect.construct() 提供了构造函数调用的反射语义。也就是说,Reflect.construct(target, argumentsList, newTarget) 在语义上等同于

js
new target(...argumentsList);

请注意,在使用 new 运算符时,targetnewTarget 始终是同一个构造函数 — 但 Reflect.construct() 允许你传递一个不同的 new.target 值。概念上,newTarget 是调用 new 的函数,而 newTarget.prototype 将成为构造对象的原型,而 target 是实际执行以初始化对象的构造函数。例如,在类继承中,new.target 也可能与当前正在执行的构造函数不同。

js
class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {}

new B(); // "B"

Reflect.construct() 允许你使用可变数量的参数调用构造函数。(这也可以在普通构造函数调用中使用 展开语法 来实现。)

js
const obj = new Foo(...args);
const obj = Reflect.construct(Foo, args);

Reflect.construct() 调用 target[[Construct]] 对象内部方法

示例

使用 Reflect.construct()

js
const d = Reflect.construct(Date, [1776, 6, 4]);
d instanceof Date; // true
d.getFullYear(); // 1776

更改 new.target

如果传递了 newTarget,它将更改构造函数内部 new.target 的值。构造的对象将是 newTarget 的实例,而不是 target 的实例。

js
function OneClass() {
  console.log("OneClass executed");
  console.log(`new.target is ${new.target.name}`);
}

function OtherClass() {
  console.log("OtherClass executed");
  console.log(`new.target is ${new.target.name}`);
}

const obj1 = Reflect.construct(OneClass, []);
// Logs:
// OneClass executed
// new.target is OneClass
console.log(obj1 instanceof OneClass); // true

const obj2 = Reflect.construct(OneClass, [], OtherClass);
// Logs:
// OneClass executed
// new.target is OtherClass
console.log(obj2 instanceof OtherClass); // true
console.log(obj2 instanceof OneClass); // false

当然,对于构造对象的原型链没有严格的保证,因为它取决于构造函数的实现。例如,如果 target 构造函数返回一个对象,那么该对象将成为构造的对象,无论 newTarget 的值是什么。如果 target 是一个带有 construct 陷阱的代理,那么该陷阱将完全控制构造过程。

js
function OneClass() {
  return { name: "one" };
}

function OtherClass() {
  return { name: "other" };
}

const obj1 = Reflect.construct(OneClass, [], OtherClass);
console.log(obj1.name); // 'one'
console.log(obj1 instanceof OneClass); // false
console.log(obj1 instanceof OtherClass); // false

有效的 new.target 应该是一个带有 prototype 属性的构造函数,但后者并未强制执行。如果 prototype 属性的值不是对象,则初始化对象将继承自 Object.prototype

js
function OneClass() {
  console.log("OneClass executed");
  console.log(`new.target is ${new.target.name}`);
}

function OtherClass() {
  console.log("OtherClass executed");
  console.log(`new.target is ${new.target.name}`);
}

OtherClass.prototype = null;

const obj = Reflect.construct(OneClass, [], OtherClass);
// Logs:
// OneClass executed
// new.target is OtherClass
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true

Reflect.construct() 与 Object.create()

在引入 Reflect 之前,可以使用任意组合的构造函数和原型来构造对象,方法是使用 Object.create()

js
function OneClass() {
  this.name = "one";
}

function OtherClass() {
  this.name = "other";
}

const args = [];
const obj1 = Reflect.construct(OneClass, args, OtherClass);
const obj2 = Object.create(OtherClass.prototype);
OneClass.apply(obj2, args);

console.log(obj1.name); // 'one'
console.log(obj2.name); // 'one'

console.log(obj1 instanceof OneClass); // false
console.log(obj2 instanceof OneClass); // false

console.log(obj1 instanceof OtherClass); // true
console.log(obj2 instanceof OtherClass); // true

然而,虽然最终结果是相同的,但过程有一个重要的区别。在使用 Object.create()Function.prototype.apply() 时,在用作构造函数的函数内部,new.target 运算符将指向 undefined,因为没有使用 new 关键字来创建对象。(实际上,它使用的是 apply 语义,而不是 construct,尽管普通函数碰巧运行方式几乎相同。)

另一方面,在调用 Reflect.construct() 时,如果提供了 newTarget 参数,new.target 运算符将指向 newTarget 参数;如果未提供,则指向 target

js
function OneClass() {
  console.log("OneClass");
  console.log(new.target);
}
function OtherClass() {
  console.log("OtherClass");
  console.log(new.target);
}

const obj1 = Reflect.construct(OneClass, args);
// Logs:
// OneClass
// function OneClass { ... }

const obj2 = Reflect.construct(OneClass, args, OtherClass);
// Logs:
// OneClass
// function OtherClass { ... }

const obj3 = Object.create(OtherClass.prototype);
OneClass.apply(obj3, args);
// Output:
//     OneClass
//     undefined

规范

规范
ECMAScript® 2026 语言规范
# sec-reflect.construct

浏览器兼容性

另见