文章目录
前言:
JavaScript 的
class
语法是 ES6(2015)引入的语法糖,用于简化原型继承的写法,使代码更接近传统面向对象语言的风格。尽管语法上更像类,但它本质上仍是基于原型的继承机制。
一、class
语法糖
1、基本语法
class Animal {
// 构造函数(创建实例时自动调用)
constructor(type) {
this.type = type;
}
// 实例方法(自动添加到原型)
speak() {
console.log(`${this.type} makes a sound`);
}
// 静态方法(属于类本身,不被实例继承)
static info() {
console.log("This is an Animal class");
}
}
// 创建实例
const cat = new Animal("Cat");
cat.speak(); // 输出: Cat makes a sound
Animal.info(); // 输出: This is an Animal class
2、核心特性
2.1、继承(extends
)
class Dog extends Animal {
constructor(name) {
super("Dog"); // 调用父类构造函数
this.name = name;
}
// 子类方法
bark() {
super.speak(); // 调用父类方法
console.log(`${this.name} barks!`);
}
}
const dog = new Dog("Buddy");
dog.bark();
// 输出:
// Dog makes a sound
// Buddy barks!
2.2、私有属性和方法(#
)
ES2022 引入的私有语法,通过
#
前缀标记:
class Person {
#age = 0; // 私有属性
constructor(name, age) {
this.name = name;
this.#age = age;
}
#privateMethod() {
console.log("This is private");
}
publicMethod() {
this.#privateMethod(); // 内部可访问
}
}
const p = new Person("Alice", 30);
console.log(p.#age); // 报错:无法访问私有属性
p.publicMethod(); // 正常调用
2.3、静态属性和方法
属于类本身,不被实例继承:
class Circle {
static PI = 3.14; // 静态属性
constructor(radius) {
this.radius = radius;
}
static area(radius) { // 静态方法
return this.PI * radius * radius;
}
}
console.log(Circle.PI); // 3.14
console.log(Circle.area(5)); // 78.5
3、与传统原型的对比
特性 | class 语法 | 传统原型 |
---|---|---|
方法定义 | 简洁的语法(speak() {...} ) | 需显式赋值到原型(Animal.prototype.speak = ... ) |
继承 | extends 关键字自动设置原型链 | 需手动设置 Child.prototype = Object.create(Parent.prototype) |
私有成员 | 支持 # 语法 | 需通过闭包或 WeakMap 模拟 |
静态成员 | 直接用 static 关键字 | 需手动添加到构造函数(如 Animal.info = ... ) |
严格模式 | 类内部默认使用严格模式 | 需要显式声明 "use strict"; |
4、本质仍是原型
尽管
class
语法更像类,但 JavaScript 仍是基于原型的语言。例如:
class MyClass {}
const obj = new MyClass();
// 验证原型关系
console.log(obj.__proto__ === MyClass.prototype); // true
console.log(MyClass.prototype.constructor === MyClass); // true
5、注意事项
在JavaScript中使用
class
语法时,虽然它简化了原型继承的写法,但仍有一些容易踩坑的细节需要注意。以下是常见的注意事项:
5.1、类不会被提升(Hoisting)
与函数声明不同,类必须先声明后使用:
const cat = new Animal(); // 报错:Animal未定义
class Animal {}
而函数声明可以被提升:
const cat = new Animal(); // 正常运行
function Animal() {}
5.2、类方法不可枚举
类中定义的方法默认不可枚举(
enumerable: false
),而传统原型方法是可枚举的:
class Animal {
speak() {}
}
function Dog() {}
Dog.prototype.bark = function() {};
console.log(Object.keys(Animal.prototype)); // []
console.log(Object.keys(Dog.prototype)); // ['bark']
5.3、必须使用new
调用类构造函数
类构造函数必须通过
new
关键字调用,否则会报错:
class Animal {
constructor() {}
}
Animal(); // 报错:Class constructor Animal cannot be invoked without 'new'
而普通函数可以直接调用:
function Animal() {}
Animal(); // 正常运行(但可能导致全局污染)
5.4、静态成员不被实例继承
静态属性和方法属于类本身,实例无法访问:
class Circle {
static PI = 3.14;
static area(r) { return this.PI * r * r; }
}
const c = new Circle();
console.log(c.PI); // undefined
console.log(c.area(5)); // 报错:c.area is not a function
5.5、子类构造函数必须调用super()
在子类构造函数中,必须先调用
super()
才能使用this
:
class Animal {
constructor(type) {
this.type = type;
}
}
class Dog extends Animal {
constructor(name) {
// 必须先调用super()
super("Dog");
this.name = name;
}
}
5.6、类方法中的this
可能丢失上下文**
类方法不会自动绑定
this
,可能导致上下文丢失:
class Button {
constructor(text) {
this.text = text;
}
click() {
console.log(`Clicked: ${this.text}`);
}
}
const btn = new Button("Submit");
const handler = btn.click;
handler(); // 报错:Cannot read property 'text' of undefined
解决方法:
- 在构造函数中绑定
this
:constructor() { this.click = this.click.bind(this); }
- 使用箭头函数(自动绑定
this
):click = () => { console.log(`Clicked: ${this.text}`); }
5.7、避免修改原生类的原型
修改内置类(如
Array
、Object
)的原型可能导致全局冲突:
// 不推荐
class MyArray extends Array {
static customMethod() { /* ... */ }
}
// 更好的做法:封装而非继承
class Wrapper {
constructor() {
this.array = [];
}
add(item) { this.array.push(item); }
}
6、总结
JavaScript 的
class
语法通过更简洁、更符合直觉的方式实现继承,但并未改变其基于原型的本质。它提供了私有成员、静态成员、继承等现代语言特性,使代码更具可读性和可维护性,尤其适合大型项目和团队协作。