A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/constructor below:

æž„é€ å‡½æ•° - JavaScript | MDN

通过构造函数,你可以在调用实例化对象的其他方法之前,提供必须完成的自定义初始化。

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

  introduce() {
    console.log(`你好,我的名字是 ${this.name}`);
  }
}

const otto = new Person("Otto");

otto.introduce(); // 你好,我的名字是 Otto

如果不指定构造函数,则使用默认的构造函数。如果你的类是基类,默认构造函数会是空的:

如果你的类是派生类,默认构造函数会调用父构造函数,并传递所提供的任何参数:

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

备注: 像上面这样的显式构造函数与默认构造函数的区别在于,后者实际上并不通过参数展开来调用数组迭代器。

这样代码才能正常工作:

class ValidationError extends Error {
  printCustomerMessage() {
    return `验证失败 :-((详细信息:${this.message})`;
  }
}

try {
  throw new ValidationError("非有效电话号码");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // 这是 Error,而不是 ValidationError!
    console.log(error.printCustomerMessage());
  } else {
    console.log("未知错误", error);
    throw error;
  }
}

ValidationError 类不需要显式构造函数,因为它不需要进行任何自定义初始化。默认构造函数会根据给定的参数初始化父类 Error 。

但是,如果你提供了自己的构造函数,而你的类派生自某个父类,那么你必须使用 super() 显式地调用父类的构造函数。例如:

class ValidationError extends Error {
  constructor(message) {
    super(message); // 调用父类构造函数
    this.name = "ValidationError";
    this.code = "42";
  }

  printCustomerMessage() {
    return `发生未知错误 :-((详细信息:${this.message},错误代码:${this.code})`;
  }
}

try {
  throw new ValidationError("非有效手机号码");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.name); // 现在这是 ValidationError!
    console.log(error.printCustomerMessage());
  } else {
    console.log("未知错误", error);
    throw error;
  }
}

在类中使用 new,需要经过以下步骤:

  1. (如果是派生类)super() 调用之前的 constructor 主体。这部分不应访问 this,因为它尚未初始化。
  2. (如果是派生类)执行 super() 调用,通过同样的过程初始化父类。
  3. 当前类的字段将被初始化。
  4. 执行调用 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
    // 这并不是因为 class 没有声明它,
    // 而是由于私有字段在父类构造函数运行的时候尚未初始化
  }
})();

constructor 方法可能有返回值。基类可以在构造函数中返回任何值,而派生类必须返回一个对象、 undefined 值,或抛出 TypeError。

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

console.log(new ParentClass()); // ParentClass {}
// 因为返回值不是一个对象,所以它会被忽略
// 这与函数构造函数一致

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(`你好,我的名字是 ${this.name}`);
  }
}

const person = new Person();
person.introduce(); // 你好,我的名字是 Anonymous

构造函数必须是一个明确的值。计算属性不能成为构造函数。

class Foo {
  // 这是一个计算属性。它不会作为构造函数被拾取。
  ["constructor"]() {
    console.log("被调用");
    this.a = 1;
  }
}

const foo = new Foo(); // 无日志
console.log(foo); // Foo {}
foo.constructor(); // 记录“被调用”
console.log(foo); // Foo { a: 1 }

禁止将异步方法、生成器方法、访问器和类字段称为 constructor。私有名称不能被命名为 #constructor。任何名为 constructor 的成员都必须是普通方法。


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4