constructor
constructor 方法是 類 的一個特殊方法,用於建立和初始化該類的物件例項。
注意:本頁面介紹 constructor 語法。有關所有物件上存在的 constructor 屬性,請參閱 Object.prototype.constructor。
試一試
class Polygon {
constructor() {
this.name = "Polygon";
}
}
const poly = new Polygon();
console.log(poly.name);
// Expected output: "Polygon"
語法
constructor() { /* … */ }
constructor(argument0) { /* … */ }
constructor(argument0, argument1) { /* … */ }
constructor(argument0, argument1, /* …, */ argumentN) { /* … */ }
還有一些額外的語法限制
描述
建構函式使你能夠提供任何自定義初始化,這些初始化必須在例項化物件上呼叫任何其他方法之前完成。
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
如果你沒有提供自己的建構函式,那麼會為你提供一個預設建構函式。如果你的類是一個基類,預設建構函式是空的。
constructor() {}
如果你的類是一個派生類,預設建構函式會呼叫父建構函式,並傳遞提供的任何引數。
constructor(...args) {
super(...args);
}
這使得以下程式碼可以工作:
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() 顯式呼叫父類建構函式。例如:
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 會經歷以下步驟:
- (如果是派生類)在呼叫
super()之前,會評估constructor主體。這部分不應訪問this,因為它尚未初始化。 - (如果是派生類)評估
super()呼叫,它會透過相同的過程初始化父類。 - 初始化當前類的 欄位。
- 在呼叫
super()之後(如果是基類,則是整個主體)評估constructor主體。
在 constructor 主體中,你可以透過 this 訪問正在建立的物件,並透過 new.target 訪問使用 new 呼叫的類。請注意,在執行 constructor 之前,方法(包括 getter 和 setter)和 原型鏈 已經在 this 上初始化,因此你甚至可以從超類的建構函式中訪問子類的方法。但是,如果這些方法使用 this,則 this 可能尚未完全初始化。這意味著讀取派生類的公共欄位將導致 undefined,而讀取私有欄位將導致 TypeError。
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。
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 遵循正常的方法語法,因此可以使用引數預設值、剩餘引數等。
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
建構函式必須是字面名稱。計算屬性不能成為建構函式。
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 的成員都必須是一個普通方法。
示例
使用建構函式
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() 呼叫哪個建構函式。
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 |
瀏覽器相容性
載入中…