视频加载失败

ES6类Class

2528 字
13 分钟
ES6类Class

Class 是什么#

JavaScript 的 Class(类)本质上是:对“构造函数 + 原型链”的语法糖封装,更接近“面向对象语言”的写法(比如 Java / C++)来写 JS,但底层机制还是原型(prototype)。

基本用法:

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`我叫${this.name}`);
}
}
//使用
const p1 = new Person('张三', 18);
p1.sayHello();//this指向p1

class与构造函数:

//旧写法
function Person(name) {
this.name = name;
}
Person.prototype.say = function () {
console.log(this.name);
};
//新写法
class Person {
constructor(name) {
this.name = name;
}
say() {
console.log(this.name);
}
}

constructor 是什么

//new 的时候自动执行
//用来初始化对象
//默认的构造函数,可不写,但是每个类都会有
class A {
constructor() {
console.log('我会在 new 的时候执行');
}
}
new A();

不建议把方法放到constructor中

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
////一般构造方法定义属性,方法不在构造函数中定义
this.speak = () => {};
}
sayHello() {
console.log(`我叫${this.name}`);
}
}
const p1 = new Person();
const p2 = new Person();
//不建议把方法放在constructor,因为每new一个对象实例就会占用内存
console.log(p1.speak === p2.speak); //false
console.log(p1.sayHello === p2.sayHello); //true

Class 的两种定义形式#

类声明和类表达式区别

特性类声明类表达式
语法class Person {}const Person = class {}
是否有名字必须有可匿名、可命名
变量提升❌ 无❌ 无
是否可以赋值给变量默认就是标识符通常赋值给变量
使用场景普通定义类动态创建类、工厂模式

类声明

class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}`);
}
}
const p = new Person('张三');
p.sayHello();

类表达式

const Person = class {
constructor(name) {
this.name = name;
}
};
const p = new Person('张三');

两个注意点:

不存在声明提升

一样可以跟函数一样立即执行,但是需要new

//不存在声明提升
//ReferenceError: Cannot access 'Person' before initialization
const p = new Person('张三');
const Person = class {
constructor(name) {
this.name = name;
}
};
//一样可以跟函数一样立即执行,但是需要new
new (class {
constructor(name) {
this.name = name;
}
}('张三'))

实例属性、静态方法和静态属性#

实例的东西属于对象,静态的东西属于类

实例属性:实例属性是每个对象自己拥有的属性。

class Person {
name = 'alex'; //实例属性,默认值
age = 0; //实例属性,默认值
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const p1 = new Person('张三', 18);
const p2 = new Person('李四', 20);
console.log(p1.name);
console.log(p2.name);

实例方法:

//注意,实例方法只能实例调用,不能类调用,如Person.sayHello()就错误了
class Person {
name = 'alex'; //实例属性,默认值
age = 0; //实例属性,默认值
sayHello() {
console.log(`helle ${this.name}`);
} //实例方法
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const p1 = new Person('张三', 18);
const p2 = new Person('李四', 20);
console.log(p1.name);
console.log(p2.name);
p1.sayHello();
p2.sayHello();

静态方法:使用 static 定义

//静态方法不能实例调用
class Person {
name = 'alex'; //实例属性,默认值
age = 0; //实例属性,默认值
static sayHello() {
console.log(`helle ${this.name}`);
} //实例方法
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const p1 = new Person('张三', 18);
const p2 = new Person('李四', 20);
console.log(p1.name);
console.log(p2.name);
Person.sayHello(); //helle Person 类名字,静态就是静

静态属性:ES2022 支持直接写

class Person {
static country = '中国';
}
console.log(Person.country);//中国

私有属性和方法#

JavaScript 的私有属性和私有方法(Private Fields & Methods),是 ES2022 正式支持的语法,用 # 开头表示。只能在类的内部访问,类的外部无法访问和修改。类似于 Java 里的 private。

为什么需要私有属性:

//假设有一个银行账户类:
class Account {
constructor(balance) {
this.balance = balance;
}
}
const a = new Account(1000);
a.balance = 100000000;
//外部可以随意修改:1000 → 100000000这显然不安全。

私有属性(#)

class Account {
#balance;
constructor(balance) {
this.#balance = balance;
}
getBalance() {
return this.#balance;
}
}
const a = new Account(1000);
console.log(a.getBalance());//1000
//外部访问
console.log(a.#balance);//直接报错
//外部修改
a.#balance = 9999;//也是语法错误。

私有方法(#)

class Person {
#sayHello() {
console.log('hello');
}
greet() {
this.#sayHello();
}
}
const p = new Person();
p.greet();//hello
//外部调用
p.#sayHello();//直接报错

私有静态属性

class Person {
static #count = 0;
constructor() {
Person.#count++;
}
static getCount() {
return Person.#count;
}
}
new Person();
new Person();
console.log(Person.getCount());//2
//外部调用
console.log(Person.#count);//报错

私有静态方法

class Person {
static #hello() {
console.log('hello');
}
static say() {
Person.#hello();
}
}
Person.say();//hello

注意点:

//必须声明私有变量
//错误示范
class Person {
constructor() {
this.#name = '张三';
}
}
//正确
class Person {
#name;//声明私有
constructor() {
this.#name = '张三';
}
}
//只能在类内部访问
class Person {
#name = '张三';
show() {
console.log(this.#name);
}
}
//子类不能直接访问父类私有属性
class A {
#x = 1;
}
class B extends A {
test() {
console.log(this.#x);
}
}
//获取设置私有数据的方法
class Person {
#name;
constructor(name) {
this.#name = name;
}
getName() {
return this.#name;
}
setName(name) {
this.#name = name;
}
}
//输出什么?undefined
//为什么?p.name和p.#name不是一个东西,实例上没有name所以是undefined如果是p.#name就报错
class Person {
#name = '张三';
}
const p = new Person();
console.log(p.name);

至于之前的“古法”模拟私有变量,这里不展开讲解

extends#

extends 是 JavaScript 中实现类继承的关键字。子类继承父类的属性和方法。

基本语法:

class 父类 {}
class 子类 extends 父类 {}

示例:

class Animal {
eat() {
console.log('吃东西');
}
}
class Dog extends Animal {}
const dog = new Dog();
dog.eat();//吃东西

继承构造函数

class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
const dog = new Dog('旺财');
console.log(dog.name);//旺财

方法重写

class Animal {
speak() {
console.log('动物叫');
}
}
class Dog extends Animal {
speak() {
console.log('汪汪');
}
}
new Dog().speak();//汪汪
//如果想保留父类逻辑
class Dog extends Animal {
speak() {
super.speak();//保留父类逻辑
console.log('汪汪');
}
}

注意点:super前面不能有this操作

super#

一句话记忆:

constructor:
super() = 调父类构造函数
实例方法:
super = 父类.prototype
静态方法:
super = 父类

super 有两种用法:在 constructor 中和在普通方法中

在 constructor 中:

class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, age) {
super(name);
this.age = age;
}
}
const d = new Dog('旺财', 2);
console.log(d);
//输出
Dog {
name: '旺财',
age: 2
}

为什么必须先写 super?:在子类中:this不是一开始就存在的。必须:super()执行后,JS 才创建出 this。可以理解成

class Dog extends Animal {
constructor(name) {
super(name);
}
}
//概念上类似:
function Dog(name) {
Animal.call(this, name);
}

只是概念上类似,底层不是直接 call。

普通方法中的 super

class Animal {
eat() {
console.log('动物吃东西');
}
}
class Dog extends Animal {
eat() {
super.eat();//相当于:Animal.prototype.eat.call(this)
console.log('吃骨头');
}
}
new Dog().eat();
//动物吃东西
//吃骨头

super 不是父类实例

很多人以为:super等于:new Animal();其实不是

class Animal {
eat() {
console.log(this);
}
}
class Dog extends Animal {}
new Dog().eat();//Dog {}

说明:this还是Dog 的实例,所以:super.eat()其实是:Animal.prototype.eat.call(this)

super 访问父类属性

class Animal {
name = '动物';
}
class Dog extends Animal {
show() {
console.log(super.name);//undefined
}
}

很多人会懵。因为:super指向Animal.prototype,而name是实例属性this.name不在:Animal.prototype上

例子:

class Animal {
eat() {}
}
Animal.prototype = {
eat() {}
}
super.eat//能找到
//但是:name是实例属性,不在原型上 super.name就是undefined
class Animal {
name = '动物';
constructor() {
this.name = '动物';
}
}

super 调用静态方法

class Animal {
static hello() {
console.log('hello');
}
}
class Dog extends Animal {
static hi() {
super.hello();
}
}
Dog.hi();

这里:super指向Animal,而不是Animal.prototype

super 的this指向总结

  • 在实例方法中,super指向:父类.prototype
  • 在静态方法中,super指向:父类本身
  • 在 constructor 中,作用是调用父类构造函数,创建 this

Class的应用#

一、创建对象模板(最基本的应用)

例如:用户。

class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
login() {
console.log(`${this.name} 登录了`);
}
}
const u1 = new User('张三', 18);
const u2 = new User('李四', 20);
u1.login();
u2.login();

这里:

User
↓
创建多个用户对象

二、封装业务对象

例如:购物车。

class Cart {
constructor() {
this.goods = [];
}
add(item) {
this.goods.push(item);
}
remove(id) {
this.goods = this.goods.filter(
item => item.id !== id
);
}
getTotal() {
return this.goods.reduce(
(sum, item) => sum + item.price,
0
);
}
}

使用:

const cart = new Cart();
cart.add({
id: 1,
price: 100
});
console.log(cart.getTotal());

三、封装组件(前端很常见)

例如自己实现一个弹窗:

class Modal {
open() {
console.log('打开弹窗');
}
close() {
console.log('关闭弹窗');
}
}
const modal = new Modal();
modal.open();
modal.close();

四、工具类(静态方法)

例如:

class MathUtil {
static add(a, b) {
return a + b;
}
static sub(a, b) {
return a - b;
}
}
MathUtil.add(1, 2);

实际上 JS 内置对象就是这样:

  • Math
  • Date
  • Object
  • Array

例如:

Math.max(1, 2);
Date.now();
Object.keys(obj);
Array.isArray(arr);

这些都是静态方法。

五、数据模型(Model)

例如:

class User {
constructor(data) {
this.id = data.id;
this.name = data.name;
this.email = data.email;
}
isAdmin() {
return this.role === 'admin';
}
}

接口:

const res = {
id: 1,
name: '张三',
role: 'admin'
};
const user = new User(res);
console.log(user.isAdmin());

六、继承(extends)

例如:

class Animal {
eat() {
console.log('吃');
}
}
class Dog extends Animal {
bark() {
console.log('汪汪');
}
}
class Cat extends Animal {
meow() {
console.log('喵喵');
}
}

这样:

共同逻辑
↓
放父类
特殊逻辑
↓
放子类

七、游戏开发(非常常见)

class Player {
move() {}
}
class Warrior extends Player {
attack() {}
}
class Mage extends Player {
cast() {}
}

很多游戏引擎大量使用 class。

八、Node.js 后端开发

例如:

class UserService {
async login() {}
async register() {}
}
class UserController {
async login(req, res) {}
}

很多框架都喜欢这种写法,例如:

  • NestJS
  • Angular

九、React 早期开发

以前大量使用类组件:

class App extends React.Component {
state = {
count: 0
};
render() {
return <div>Hello</div>;
}
}

虽然现在:

Hooks > Class Component

但很多老项目还有大量 class。

十、继承内置类

例如:

class MyArray extends Array {
first() {
return this[0];
}
}
const arr = new MyArray(1, 2, 3);
console.log(arr.first());

十一、设计模式(面试加分)

单例模式

class Singleton {
static instance;
static getInstance() {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}

工厂模式

class User {
constructor(name) {
this.name = name;
}
static create(name) {
return new User(name);
}
}

十二、什么时候不建议用 class?

例如:

function add(a, b) {
return a + b;
}
//或者:
const formatDate = () => {};

这种纯函数 没必要写成:

class Utils {
add() {}
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

ES6类Class
https://f.youzi177.cn/posts/20261021012es6-lei-class/
作者
小封鸭
发布于
2026-10-21
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
小封鸭
小楼一夜听春雨,深巷明朝卖杏花
公告
欢迎来到我的博客。这里主要记录前端全栈和日常内容
分类
标签
最新动态
站点统计
文章
60
分类
3
标签
12
总字数
107,734
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
EdgeOne Pages
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录