constructor方法
constructor方法的基本概念
constructor方法是ECMAScript 6中类(class)的构造函数,用于创建和初始化类创建的对象。当通过new关键字实例化一个类时,constructor方法会被自动调用。这个方法在类中是特殊的,它既不是静态方法也不是实例方法。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const person1 = new Person('张三', 25);
console.log(person1.name); // 输出: 张三
constructor方法的特性
constructor方法有几个重要特性需要注意:
- 每个类只能有一个constructor方法,否则会抛出SyntaxError
- 如果没有显式定义constructor方法,JavaScript会提供一个默认的constructor
- constructor方法默认返回实例对象(this),但可以返回其他对象
class Animal {
// 没有显式定义constructor
}
const animal = new Animal();
// JavaScript会自动添加如下constructor:
// constructor() {}
constructor方法的参数
constructor方法可以接受任意数量的参数,这些参数在实例化类时传递:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.height * this.width;
}
}
const rect = new Rectangle(10, 20);
console.log(rect.area); // 输出: 200
constructor中的super调用
在继承的类中,constructor方法必须先调用super()才能使用this关键字:
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 必须先调用super
this.breed = breed;
}
}
const myDog = new Dog('旺财', '金毛');
console.log(myDog.name); // 输出: 旺财
constructor返回值的特殊情况
虽然constructor通常不显式返回值,但如果返回一个对象,则该对象会替代默认创建的实例:
class Foo {
constructor() {
return { bar: 'baz' };
}
}
const foo = new Foo();
console.log(foo); // 输出: { bar: 'baz' }
console.log(foo instanceof Foo); // 输出: false
constructor与原型方法
constructor方法与其他类方法不同,它不会被添加到类的原型上:
class Example {
constructor() {}
method() {}
}
console.log(Example.prototype.method); // 输出: [Function: method]
console.log(Example.prototype.constructor); // 输出: [class Example]
constructor的默认实现
当类没有显式定义constructor时,JavaScript引擎会根据情况自动添加不同的默认constructor:
// 基类
class Base {}
// 相当于:
// class Base {
// constructor() {}
// }
// 派生类
class Derived extends Base {}
// 相当于:
// class Derived extends Base {
// constructor(...args) {
// super(...args);
// }
// }
constructor中的属性初始化
ES6支持直接在类中定义实例属性,这可以替代部分constructor中的初始化代码:
class OldWay {
constructor() {
this.counter = 0;
}
}
class NewWay {
counter = 0; // 类字段提案
}
const old = new OldWay();
const newWay = new NewWay();
console.log(old.counter, newWay.counter); // 输出: 0 0
constructor与私有字段
ES2022引入了私有字段,这些字段必须在constructor之前声明,且只能在类内部访问:
class Counter {
#count = 0; // 私有字段
constructor(initialValue) {
if (initialValue !== undefined) {
this.#count = initialValue;
}
}
increment() {
this.#count++;
}
get value() {
return this.#count;
}
}
const counter = new Counter(5);
counter.increment();
console.log(counter.value); // 输出: 6
console.log(counter.#count); // 报错: Private field '#count' must be declared in an enclosing class
constructor与静态初始化块
ES2022引入了静态初始化块,可以用于复杂的静态属性初始化:
class MyClass {
static x;
static y;
static {
// 可以访问私有静态字段
try {
const result = someComplexInitialization();
this.x = result.x;
this.y = result.y;
} catch {
this.x = 0;
this.y = 0;
}
}
constructor() {
// 实例初始化
}
}
constructor的性能考虑
constructor方法的性能会影响对象的创建速度,特别是在频繁创建实例的场景下:
class Optimized {
constructor(a, b) {
this.a = a;
this.b = b;
// 避免在constructor中做复杂计算
}
}
class Unoptimized {
constructor(a, b) {
this.a = a;
this.b = b;
this.c = this.computeSomething(); // 复杂计算放在constructor中会影响性能
}
computeSomething() {
let result = 0;
for (let i = 0; i < 1000000; i++) {
result += Math.random();
}
return result;
}
}
constructor与继承链
在复杂的继承关系中,constructor的调用顺序遵循原型链:
class A {
constructor() {
console.log('A constructor');
}
}
class B extends A {
constructor() {
super();
console.log('B constructor');
}
}
class C extends B {
constructor() {
super();
console.log('C constructor');
}
}
const c = new C();
// 输出:
// A constructor
// B constructor
// C constructor
constructor与new.target
new.target元属性可以在constructor中检测类是如何被调用的:
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('Shape类不能直接实例化');
}
}
}
class Circle extends Shape {}
// new Shape(); // 报错: Shape类不能直接实例化
new Circle(); // 正常
constructor与异步初始化
虽然不常见,但constructor可以包含异步操作,不过需要注意返回Promise的情况:
class AsyncExample {
constructor() {
return (async () => {
await someAsyncOperation();
return this; // 必须返回this
})();
}
}
// 使用时需要await
(async () => {
const instance = await new AsyncExample();
})();
constructor与代理
可以通过Proxy来拦截constructor的调用:
class Base {
constructor(value) {
this.value = value;
}
}
const Handler = {
construct(target, args) {
console.log(`创建实例,参数: ${args}`);
return new target(...args);
}
};
const ProxiedClass = new Proxy(Base, Handler);
const instance = new ProxiedClass(42); // 输出: 创建实例,参数: 42
constructor与装饰器
使用装饰器可以修改类的constructor行为:
function logConstructor(target) {
const original = target.prototype.constructor;
target.prototype.constructor = function(...args) {
console.log(`创建实例,参数: ${args}`);
return original.apply(this, args);
};
return target;
}
@logConstructor
class MyClass {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
const obj = new MyClass(1, 2); // 输出: 创建实例,参数: 1,2
constructor与类表达式
类表达式中的constructor与类声明中的行为一致:
const Person = class {
constructor(name) {
this.name = name;
}
};
const person = new Person('李四');
console.log(person.name); // 输出: 李四
constructor与生成器方法
虽然constructor本身不能是生成器函数,但可以在其中调用生成器方法:
class Sequence {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const seq = new Sequence(1, 5);
console.log([...seq]); // 输出: [1, 2, 3, 4, 5]
constructor与Symbol.species
可以通过Symbol.species覆盖constructor,用于派生集合对象:
class MyArray extends Array {
static get [Symbol.species]() {
return Array; // 覆盖默认的constructor
}
constructor(...args) {
super(...args);
}
}
const myArray = new MyArray(1, 2, 3);
const mapped = myArray.map(x => x * 2);
console.log(mapped instanceof MyArray); // 输出: false
console.log(mapped instanceof Array); // 输出: true
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:class关键字基本语法
下一篇:静态方法和属性