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

瀏覽器相容性

另見