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指向p1class与构造函数:
//旧写法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); //falseconsole.log(p1.sayHello === p2.sayHello); //trueClass 的两种定义形式
类声明和类表达式区别
| 特性 | 类声明 | 类表达式 |
|---|---|---|
| 语法 | 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 initializationconst p = new Person('张三');const Person = class { constructor(name) { this.name = name; }};//一样可以跟函数一样立即执行,但是需要newnew (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就是undefinedclass 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() {}}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














