理解 JavaScript Class 之前,必须先掌握这 3 个基础概念

更新日期: 2026-03-25 阅读: 22 标签: class

在学习 Class 之前,有必要先了解以下三个基础概念,这是理解 Class 的关键,也是避免“知其然不知其所以然”的核心。


1. 面向对象编程(OOP)

面向对象编程是一种编程思想,将程序的核心逻辑拆分成一个个对象。每个对象包含属性(存储数据,如人的姓名、年龄)和方法(执行行为,如人的说话、走路)。OOP 有三大核心特性:封装、继承、多态(本文重点讲封装和继承)。其核心优势在于代码复用和易维护性。


2. 原型链

原型链是 JavaScript 的原生继承机制。JS 中所有对象都有一个隐藏的 __proto__ 属性,指向它的原型对象;原型对象也有自己的 __proto__,最终指向 Object.prototype,这条链式结构就是原型链。Class 的底层实现完全依赖原型链,它只是原型链的“表层简化写法”。


3. 语法

语法糖是指不改变语言底层逻辑,仅简化代码写法的语法。JS 的 Class 没有新增任何 OOP 功能,只是将 ES5 的“构造函数 + 原型”写法封装成了更直观的结构,让开发更高效。


ES5 的痛点:为什么需要 Class?

在 ES6 之前,实现一个简单的“人”对象模型,需要分开写构造函数(定义属性)和原型(挂载方法),代码分散、语义模糊,新手容易绕晕:

// ES5 构造函数 + 原型实现 OOP
function Person(name) {
  this.name = name; // 构造函数定义属性
}
// 原型上挂载方法,所有实例共享
Person.prototype.introduceSelf = function() {
  console.log(`Hi! I'm ${this.name}`);
};
// 实例化
const giles = new Person("Giles");
giles.introduceSelf(); // Hi! I'm Giles

而 ES6 的 Class 能将属性和方法集中在一个代码块中,写法更符合人类的思维习惯,这也是 Class 出现的核心原因。


一、类与构造器:Class 的基础用法

class 是 ES6 新增的关键字,用于声明一个类。类是创建对象(实例)的“模板”,例如 Person 类可以创建出无数个具体的人(giles、tom 等)。

其中构造器(constructor)是类的核心,专门负责初始化实例的属性,是类中最特殊的方法。

1. 基本类声明语法

一个完整的基础类包含属性声明、构造器、实例方法,结构集中且直观:

// ES6 Class 基础写法
class Person {
  name; // 显式声明属性(可选,推荐写,增强可读性)
  // 构造器:new 调用类时自动执行
  constructor(name) {
    this.name = name; // this 指向新建的实例对象
  }
  // 实例方法:无需 function 关键字,直接写方法名
  introduceSelf() {
    console.log(`Hi! I'm ${this.name}`);
  }
}
// 实例化:new + 类名 → 调用构造器创建实例
const giles = new Person("Giles");
giles.introduceSelf(); // Hi! I'm Giles

2. 核心细节

(1)属性的 3 种声明方式

属性声明并非强制要求,但显式声明能让阅读者一眼看到类的所有属性,推荐使用。三种方式均有效:

  • 显式空声明:name;

  • 显式赋默认值:name = '未知';(实例化未传值时用默认值)

  • 隐式声明:不写 name;,直接在构造器中 this.name = name;(构造器会自动创建属性)

(2)构造器的固定作用

构造器是类的唯一特殊方法,不可重名。new 关键字调用类时,会自动执行以下 4 步,无需手动控制:

  1. 创建一个空的新对象

  2. 将 this 绑定到这个新对象(所以 this 指向实例)

  3. 执行构造器代码,为新对象添加属性

  4. 返回这个新对象

(3)省略构造器的情况

如果类不需要初始化任何属性,可直接省略 constructor,JavaScript 会自动生成一个无参的默认构造器:

// 无构造器 → 自动生成默认构造器
class Animal {
  sleep() {
    console.log("zzzzzzz");
  }
}
const spot = new Animal(); // 无需传参
spot.sleep(); // zzzzzzz

3. 注意事项

  • 类的方法之间无需加逗号,加了会报语法错误(区别于对象字面量)

  • 实例化类必须用 new 关键字,直接调用类(如 Person("Giles"))会报错

  • 类的声明无变量提升,必须先声明类,再实例化(区别于函数声明)

4. 类中的属性和方法默认存储位置

  • 属性:存储在每个实例中,是实例自有的

  • 方法:存储在原型对象中,所有实例共享同一个方法


二、继承:extends + super,实现代码复用

继承是 OOP 的核心特性,指子类(派生类)继承父类(基类)的所有公共属性和方法,同时子类可新增自己的属性/方法,或重写父类的方法。其核心目的是实现代码复用,避免重复编写相同逻辑。

JS 中实现继承的两个核心语法:extends(声明继承关系)、super()(调用父类构造器),缺一不可。

1. 基本继承语法

以 Professor(教授)子类继承 Person(人)父类为例:

// 父类:Person
class Person {
  name;
  constructor(name) {
    this.name = name;
  }
  introduceSelf() {
    console.log(`Hi! I'm ${this.name}`);
  }
}
// 子类:Professor 继承 Person → extends 关键字
class Professor extends Person {
  teaches; // 子类新增属性
  // 子类构造器:接收父类 + 自己的参数
  constructor(name, teaches) {
    super(name); // 必须先调用 super,传父类构造器的参数
    this.teaches = teaches; // 再初始化子类属性
  }
  // 重写父类的 introduceSelf 方法
  introduceSelf() {
    console.log(`My name is ${this.name}, I teach ${this.teaches}.`);
  }
  // 子类新增方法
  grade(paper) {
    const score = Math.floor(Math.random() * 4 + 1); // 1-4 随机分数
    console.log(`论文${paper}分数:${score}`);
  }
}
// 实例化子类,需传父类 + 子类的所有参数
const walsh = new Professor("Walsh", "Psychology");
walsh.introduceSelf(); // My name is Walsh, I teach Psychology.
walsh.grade("心理学导论"); // 论文心理学导论分数:3

2. 继承的核心规则

(1)super() 的强制调用规则

如果子类有自己的构造器,必须在构造器第一行调用 super(),否则直接报错。原因:JS 引擎强制要求先将父类的属性初始化添加到当前 this,才能继续初始化自己的属性。super() 的本质相当于使用 call 方法调用父类构造函数,将 this 指向子类实例:Person.call(this, name);

(2)super() 的传参规则

super() 的参数必须和父类构造器的参数完全一致,父类需要什么参数,super() 就传什么。子类自己的参数在 super() 后单独处理。

(3)方法重写与多态

子类的方法名和父类一致时,会覆盖父类的方法,这是 OOP 多态特性的体现——同一个方法,在父类和子类中有不同的实现,适配不同的场景。

(4)属性/方法的访问规则

子类实例可以访问父类的所有公共属性/方法,也可以访问自己的,遵循就近原则:先找子类自身,找不到再向上找父类。

(5)extends 和 super 的底层原理

  • extends:相当于使用 Object.create() 继承父类的原型对象

    Professor.prototype = Object.create(Person.prototype);
  • super:相当于使用 call 方法调用父类构造函数,将 this 指向子类实例

3. 继承的原型链本质

Class 的继承底层仍是原型链,只是 JS 自动帮我们做了原型链的关联。


三、封装:# 私有字段/方法,实现数据保护

封装是 OOP 的核心特性,指将对象的私有数据隐藏起来,只对外暴露公共的访问方法,避免外部代码随意修改内部属性导致程序逻辑混乱。

JS 的原生封装能力经历了一个发展过程:

  • ES6 及之前:无原生私有属性,开发者只能通过约定(如属性名加下划线 _year)模拟私有,无法真正阻止外部修改

  • ES2022(ES13):正式支持原生私有字段/方法,用 # 作为前缀,实现真正的封装

1. 私有字段的使用

私有字段的关键是 # 前缀,声明和使用时都必须加,外部代码访问会直接报语法错误:

// 父类:Person
class Person {
  name;
  constructor(name) {
    this.name = name;
  }
}
// 子类:Student,封装 #year 私有字段
class Student extends Person {
  #year; // 私有字段:必须显式声明,加 #
  constructor(name, year) {
    super(name);
    this.#year = year; // 初始化私有字段,加 #
  }
  // 公共方法:类内部可访问私有字段
  introduceSelf() {
    console.log(`Hi! I'm ${this.name}, I'm in year ${this.#year}.`);
  }
  // 公共方法:通过业务逻辑控制私有字段的使用
  canStudyArchery() {
    return this.#year > 1; // 只有年级 > 1 才能学射箭
  }
}
// 实例化
const summers = new Student("Summers", 2);
summers.introduceSelf(); // Hi! I'm Summers, I'm in year 2.
summers.canStudyArchery(); // true

// 外部访问私有字段 → 语法错误
summers.#year; // Uncaught SyntaxError

2. 私有方法的使用

私有方法同样用 # 前缀,只能在类内部被调用:

class Example {
  // 公共方法:对外暴露
  somePublicMethod() {
    this.#somePrivateMethod(); // 内部调用私有方法
  }
  // 私有方法:封装内部逻辑
  #somePrivateMethod() {
    console.log("这是私有方法,仅类内部可调用!");
  }
}
const myExample = new Example();
myExample.somePublicMethod(); // 这是私有方法,仅类内部可调用!
myExample.#somePrivateMethod(); // 语法错误,外部无法访问

3. 私有成员的核心规则

  • 必须显式声明:私有字段/方法必须在类的顶部声明,不能在构造器中临时创建

  • # 是标识符的一部分:#year 和 year 是两个完全不同的属性,不可混用

  • 无继承性:子类无法访问父类的私有成员,只能访问父类的公共成员

  • 控制台特殊情况:Chrome 开发者控制台为了调试,放松了私有成员的访问限制,但实际开发中(普通脚本)仍遵循原生规则

4. 封装的核心价值

  • 避免外部代码随意修改内部属性,导致业务逻辑失效

  • 当需要修改私有成员的业务规则时,只需修改类内部的代码,无需修改所有外部调用的代码,大幅降低维护成本


四、JavaScript Class 核心总结

  1. 底层本质:Class 是原型链的语法糖,未改变 JS 的原生机制,仅简化写法

  2. 核心语法:class 声明类,constructor 初始化属性,extends 声明继承,super() 调用父类构造器,# 定义私有成员

  3. 核心特性:完美实现 OOP 的封装、继承、多态,让 JS 的 OOP 更直观

  4. 使用优势:代码结构集中、语义清晰、易读易维护,大幅降低 OOP 学习和开发成本

  5. 使用场景:需要创建多个具有相同属性/方法的对象时(如用户、商品、课程),用 Class 实现效率最高


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13503

相关推荐

ES6 class创建对象和传统方法生成对象的区别

JS语言传统创建对象的方法一般是通过构造函数,来定义生成的,下面是一个使用function生成的例子。ES5是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数

classList介绍和原生JavaScript实现addClass、removeClass等

使用jQuery可以给元素很方便的添加class和删除class等操作,现在原生的JavaScript也可以实现这个方法了。使用classList可以方便的添加class、删除class、查询class等。elementClasses 是一个 DOMTokenList 表示 element 的类属性 。

es6新特性之 class 基本用法

ES6 提供了更接近传统语言的写法,引入了 class(类)这个概念,作为对象的模板。通过class关键字,可以定义类

class 类 this指向的问题

ES6中的 class定义一个类, 其内部包含 constructor构造函数, 除了在构造函数显示的定义一些属性, 其余的默认都添加到这个类的原型对象上。以上代码 classProxy(prosen2) 返回的是包含一层拦截器的实例对象, 当读取 sayName这个函数的是和会出发 get拦截等操作。

ES6 static

ES6中新增了class这个语法糖。此class并非java中的class,ES6中的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。其中有static关键字。

JS 总结之class

class 是 ES6 的新特性,可以用来定义一个类,实际上,class 只是一种语法糖,它是构造函数的另一种写法。用法和使用构造函数一样,通过 new 来生成对象实例

mixin配合class实现多继承的绝佳妙用

mixin一般翻译为“混入”、“混合”, 早期一般解释为:把一个对象的方法和属性拷贝到另一个对象上;Mixin是一种思想,用来实现代码高度可复用性,又可以用来解决多继承的问题,是一种非常灵活的设计模式

Class 的私有属性与私有方法

proposal-class-fields与proposal-private-methods定义了 Class 的私有属性以及私有方法,这 2 个提案已经处于 Stage 3,这就意味着它们已经基本确定下来了,等待被加入到新的 ECMAScript 版本中。

你需要知道的 JavaScript 类(class)的这些知识

JavaScript 使用原型继承:每个对象都从原型对象继承属性和方法。在Java或Swift等语言中使用的传统类作为创建对象的蓝图,在 JavaScript 中不存在,原型继承仅处理对象。

Class:向传统类模式转变的构造函数

JS基于原型的类,一直被转行前端的码僚们大呼惊奇,但接近传统模式使用class关键字定义的出现,ES6的class只是个语法糖,其定义生成的对象依然构造函数。不过为了与构造函数模式区分开,我们称其为类模式。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!