class关键字基本语法
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
可以使用get
和set
关键字对某个属性设置取值函数和存值函数,拦截属性的存取行为。
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
类的注意事项
- 类内部默认就是严格模式
- 类不存在变量提升
- 类的方法都是不可枚举的
- 类的所有实例共享一个原型对象
- 可以通过
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
上一篇:Promise的微任务队列特性
下一篇:constructor方法