constructor

Baseline 已廣泛支援

此特性已經非常成熟,並且適用於許多裝置和瀏覽器版本。自 2016 年 3 月以來,它已在所有瀏覽器中可用。

constructor 方法是 的一個特殊方法,用於建立和初始化該類的物件例項。

注意:本頁面介紹 constructor 語法。有關所有物件上存在的 constructor 屬性,請參閱 Object.prototype.constructor

試一試

class Polygon {
  constructor() {
    this.name = "Polygon";
  }
}

const poly = new Polygon();

console.log(poly.name);
// Expected output: "Polygon"

語法

js
constructor() { /* … */ }
constructor(argument0) { /* … */ }
constructor(argument0, argument1) { /* … */ }
constructor(argument0, argument1, /* …, */ argumentN) { /* … */ }

還有一些額外的語法限制

描述

建構函式使你能夠提供任何自定義初始化,這些初始化必須在例項化物件上呼叫任何其他方法之前完成。

js
class Person {
  constructor(name) {
    this.name = name;
  }

  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const otto = new Person("Otto");

otto.introduce(); // Hello, my name is Otto

如果你沒有提供自己的建構函式,那麼會為你提供一個預設建構函式。如果你的類是一個基類,預設建構函式是空的。

js
constructor() {}

如果你的類是一個派生類,預設建構函式會呼叫父建構函式,並傳遞提供的任何引數。

js
constructor(...args) {
  super(...args);
}

注意:上述顯式建構函式和預設建構函式之間的區別在於,後者實際上不會透過 引數展開 呼叫 陣列迭代器

這使得以下程式碼可以工作:

js
class ValidationError extends Error {
  printCustomerMessage() {
    return `Validation failed :-( (details: ${this.message})`;
  }
}

try {
  throw new ValidationError("Not a valid phone number");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // This is Error instead of ValidationError!
    console.log(error.printCustomerMessage());
  } else {
    console.log("Unknown error", error);
    throw error;
  }
}

ValidationError 類不需要顯式建構函式,因為它不需要進行任何自定義初始化。預設建構函式會負責根據給定的引數初始化父 Error

但是,如果你提供了自己的建構函式,並且你的類派生自某個父類,那麼你必須使用 super() 顯式呼叫父類建構函式。例如:

js
class ValidationError extends Error {
  constructor(message) {
    super(message); // call parent class constructor
    this.name = "ValidationError";
    this.code = "42";
  }

  printCustomerMessage() {
    return `Validation failed :-( (details: ${this.message}, code: ${this.code})`;
  }
}

try {
  throw new ValidationError("Not a valid phone number");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // Now this is ValidationError!
    console.log(error.printCustomerMessage());
  } else {
    console.log("Unknown error", error);
    throw error;
  }
}

對類使用 new 會經歷以下步驟:

  1. (如果是派生類)在呼叫 super() 之前,會評估 constructor 主體。這部分不應訪問 this,因為它尚未初始化。
  2. (如果是派生類)評估 super() 呼叫,它會透過相同的過程初始化父類。
  3. 初始化當前類的 欄位
  4. 在呼叫 super() 之後(如果是基類,則是整個主體)評估 constructor 主體。

constructor 主體中,你可以透過 this 訪問正在建立的物件,並透過 new.target 訪問使用 new 呼叫的類。請注意,在執行 constructor 之前,方法(包括 gettersetter)和 原型鏈 已經在 this 上初始化,因此你甚至可以從超類的建構函式中訪問子類的方法。但是,如果這些方法使用 this,則 this 可能尚未完全初始化。這意味著讀取派生類的公共欄位將導致 undefined,而讀取私有欄位將導致 TypeError

js
new (class C extends class B {
  constructor() {
    console.log(this.foo());
  }
} {
  #a = 1;
  foo() {
    return this.#a; // TypeError: Cannot read private member #a from an object whose class did not declare it
    // It's not really because the class didn't declare it,
    // but because the private field isn't initialized yet
    // when the superclass constructor is running
  }
})();

constructor 方法可以有返回值。雖然基類可以從其建構函式返回任何值,但派生類必須返回一個物件或 undefined,否則會丟擲 TypeError

js
class ParentClass {
  constructor() {
    return 1;
  }
}

console.log(new ParentClass()); // ParentClass {}
// The return value is ignored because it's not an object
// This is consistent with function constructors

class ChildClass extends ParentClass {
  constructor() {
    return 1;
  }
}

console.log(new ChildClass()); // TypeError: Derived constructors may only return object or undefined

如果父類建構函式返回一個物件,該物件將被用作 this 值,派生類的 類欄位 將在該物件上定義。這種技巧被稱為“返回覆蓋”,它允許派生類的欄位(包括私有欄位)在不相關的物件上定義。

constructor 遵循正常的方法語法,因此可以使用引數預設值剩餘引數等。

js
class Person {
  constructor(name = "Anonymous") {
    this.name = name;
  }
  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const person = new Person();
person.introduce(); // Hello, my name is Anonymous

建構函式必須是字面名稱。計算屬性不能成為建構函式。

js
class Foo {
  // This is a computed property. It will not be picked up as a constructor.
  ["constructor"]() {
    console.log("called");
    this.a = 1;
  }
}

const foo = new Foo(); // No log
console.log(foo); // Foo {}
foo.constructor(); // Logs "called"
console.log(foo); // Foo { a: 1 }

非同步方法、生成器方法、訪問器和類欄位禁止命名為 constructor。私有名稱不能命名為 #constructor。任何名為 constructor 的成員都必須是一個普通方法。

示例

使用建構函式

此程式碼片段取自 類示例即時演示)。

js
class Square extends Polygon {
  constructor(length) {
    // Here, it calls the parent class' constructor with lengths
    // provided for the Polygon's width and height
    super(length, length);
    // NOTE: In derived classes, `super()` must be called before you
    // can use `this`. Leaving this out will cause a ReferenceError.
    this.name = "Square";
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.height = value ** 0.5;
    this.width = value ** 0.5;
  }
}

在繫結到不同原型的建構函式中呼叫 super

super() 呼叫當前類的原型的建構函式。如果你更改當前類本身的原型,super() 將呼叫新原型的建構函式。更改當前類的 prototype 屬性的原型不會影響 super() 呼叫哪個建構函式。

js
class Polygon {
  constructor() {
    this.name = "Polygon";
  }
}

class Rectangle {
  constructor() {
    this.name = "Rectangle";
  }
}

class Square extends Polygon {
  constructor() {
    super();
  }
}

// Make Square extend Rectangle (which is a base class) instead of Polygon
Object.setPrototypeOf(Square, Rectangle);

const newInstance = new Square();

// newInstance is still an instance of Polygon, because we didn't
// change the prototype of Square.prototype, so the prototype chain
// of newInstance is still
//   newInstance --> Square.prototype --> Polygon.prototype
console.log(newInstance instanceof Polygon); // true
console.log(newInstance instanceof Rectangle); // false

// However, because super() calls Rectangle as constructor, the name property
// of newInstance is initialized with the logic in Rectangle
console.log(newInstance.name); // Rectangle

規範

規範
ECMAScript® 2026 語言規範
# sec-static-semantics-constructormethod

瀏覽器相容性

另見