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 |
浏览器兼容性
加载中…