阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > class关键字基本语法

class关键字基本语法

作者:陈川 阅读数:42153人阅读 分类: JavaScript

ECMAScript 6引入了class关键字,使得JavaScript的面向对象编程更加清晰和易读。class本质上是基于原型的继承的语法糖,但提供了更接近传统面向对象语言的写法。下面详细解析其语法特性、方法定义、继承机制以及相关注意事项。

class基本定义

使用class关键字可以定义一个类,类名通常采用帕斯卡命名法。类声明不会被提升,必须先定义后使用。

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

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

const john = new Person('John');
john.sayHello(); // 输出: Hello, my name is John

类体中的constructor方法是类的默认构造方法,通过new命令生成对象实例时自动调用。一个类必须有constructor方法,如果没有显式定义,JavaScript引擎会默认添加一个空的constructor

实例方法与静态方法

类中定义的方法默认都是实例方法,需要通过实例调用。使用static关键字可以定义静态方法,静态方法直接通过类调用。

class MathUtils {
  static square(x) {
    return x * x;
  }

  cube(x) {
    return x * x * x;
  }
}

console.log(MathUtils.square(3)); // 9
const math = new MathUtils();
console.log(math.cube(3)); // 27

静态方法中的this指向类本身而不是实例。静态方法常用来实现工具函数或工厂方法。

属性定义方式

ES6类中可以直接在constructor中定义实例属性,也可以在类顶层通过赋值语句定义实例属性。静态属性需要在类外部通过类名定义。

class Rectangle {
  // 实例属性新写法
  height = 0;
  
  constructor(width) {
    this.width = width;
  }

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

// 静态属性
Rectangle.version = '1.0';

const rect = new Rectangle(10);
rect.height = 5;
console.log(rect.area); // 50
console.log(Rectangle.version); // '1.0'

getter与setter

可以使用getset关键字对某个属性设置取值函数和存值函数,拦截属性的存取行为。

class Temperature {
  constructor(celsius) {
    this.celsius = celsius;
  }

  get fahrenheit() {
    return this.celsius * 1.8 + 32;
  }

  set fahrenheit(value) {
    this.celsius = (value - 32) / 1.8;
  }
}

const temp = new Temperature(25);
console.log(temp.fahrenheit); // 77
temp.fahrenheit = 86;
console.log(temp.celsius); // 30

类继承

使用extends关键字实现继承,子类可以通过super关键字调用父类的构造函数和方法。

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

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 调用父类构造函数
    this.breed = breed;
  }

  speak() {
    super.speak(); // 调用父类方法
    console.log(`${this.name} barks.`);
  }
}

const dog = new Dog('Rex', 'Labrador');
dog.speak();
// 输出:
// Rex makes a noise.
// Rex barks.

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象必须先通过父类的构造函数完成塑造。

私有属性和方法

ES2022正式将私有属性和方法加入标准,通过在属性名或方法名前添加#前缀来定义私有成员。

class Counter {
  #count = 0; // 私有属性

  #increment() { // 私有方法
    this.#count++;
  }

  tick() {
    this.#increment();
    console.log(this.#count);
  }
}

const counter = new Counter();
counter.tick(); // 1
counter.tick(); // 2
console.log(counter.#count); // 报错: Private field '#count' must be declared in an enclosing class

类的注意事项

  1. 类内部默认就是严格模式
  2. 类不存在变量提升
  3. 类的方法都是不可枚举的
  4. 类的所有实例共享一个原型对象
  5. 可以通过new.target属性判断构造函数是如何被调用的
class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }
}

class Rectangle extends Shape {}

const shape = new Shape(); // 报错
const rect = new Rectangle(); // 正常

类表达式

与函数一样,类也可以使用表达式的形式定义。类表达式的类名只在类内部有效,如果省略则成为匿名类。

const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};

const inst = new MyClass();
console.log(inst.getClassName()); // "Me"
console.log(Me); // 报错: Me is not defined

Mixin模式实现

通过类继承可以实现简单的Mixin模式,这是一种将多个类的功能组合到一个类中的技术。

const Serializable = Base => class extends Base {
  serialize() {
    return JSON.stringify(this);
  }
};

const Loggable = Base => class extends Base {
  log() {
    console.log(this.toString());
  }
};

class Person {
  constructor(name) {
    this.name = name;
  }
  
  toString() {
    return `Person: ${this.name}`;
  }
}

const EnhancedPerson = Serializable(Loggable(Person));
const person = new EnhancedPerson('Alice');
person.log(); // "Person: Alice"
console.log(person.serialize()); // "{"name":"Alice"}"

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌