JS 入门通关手册(34):ES6 Class 语法与继承:从原型到面向对象糖衣

一、前言:为什么需要 class?

在 ES6 规范发布之前,JavaScript 实现面向对象编程主要依赖于“构造函数 + 原型链”的模式。这种写法虽然功能强大,但代码分散、逻辑不够直观,对于从 Java、C++ 等传统面向对象语言转过来的开发者而言,理解成本较高。

ES6 引入的 class 语法,从形式上弥补了这一缺憾。它提供了一种更清晰、更规范的面向对象写法,底层依然是基于原型的继承机制,但上层语法更加优雅,极大地提升了代码的可读性和可维护性。

二、class 基本语法

class 本质上是创建对象的模板,它整合了构造函数、实例方法和静态方法,让代码组织更清晰。

javascript

class Person {
  // 构造函数:使用 new 关键字时自动调用
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 实例方法:自动挂载到原型对象上
  sayHello() {
    console.log(`大家好,我是${this.name},今年${this.age}岁`);
  }

  // 静态方法:属于类本身,不属于实例
  static isAdult(age) {
    return age >= 18;
  }
}

// 创建实例
const p = new Person("张三", 20);
p.sayHello();

// 调用静态方法
console.log(Person.isAdult(20)); // true

核心特点:

  • 语法简洁:无需手动操作 prototype,方法自动挂载到原型链。

  • 结构清晰:构造函数、实例方法、静态方法一目了然。

  • 高可读性:更符合传统面向对象的编程习惯。

三、class 继承:extends 与 super

继承是面向对象的三大特性之一。在 ES6 中,通过 extends 关键字可以轻松实现子类对父类的继承,super 则用于调用父类的构造函数或方法。

javascript

// 父类
class Animal {
  constructor(name) {
    this.name = name;
  }

  eat() {
    console.log(`${this.name} 正在吃东西`);
  }
}

// 子类继承父类
class Dog extends Animal {
  constructor(name, breed) {
    // 注意:子类构造函数中必须先调用 super(),才能使用 this
    super(name);
    this.breed = breed;
  }

  // 子类自有方法
  bark() {
    console.log(`${this.name} 汪汪叫`);
  }
}

const dog = new Dog("旺财", "金毛");
dog.eat();   // 继承自父类
dog.bark();  // 自有方法

关键点总结:

  • 子类的 constructor 中必须先调用 super(),否则会报错。

  • super 指向父类的构造函数。

  • 子类可以重写父类的方法,实现多态。

四、class 底层原理:语法糖的本质

虽然 class 的写法看起来很像传统面向对象的类,但它的底层实现依然是原型链。通过类型检查可以轻松验证这一点:

javascript

class Person {}

console.log(typeof Person); // 'function'

const p = new Person();
console.log(p.__proto__ === Person.prototype); // true

结论:

  • class 本质上是构造函数的语法糖

  • 类中的方法依然挂载在构造函数的 prototype 属性上。

  • 继承关系仍然依靠原型链实现,没有改变 JavaScript 的原型本质。

五、class 高级特性

1. getter / setter

通过 get 和 set 关键字,可以对属性的读取和赋值进行拦截和控制。

javascript

class User {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }

  set name(val) {
    if (val.length < 2) {
      console.log("姓名长度不能小于2");
      return;
    }
    this._name = val;
  }
}

2. 静态属性

静态属性属于类本身,而不是类的实例,可以直接通过类名访问。

javascript

class User {
  static role = "user";
}

console.log(User.role); // 'user'

3. 私有属性(ES2022 正式特性)

以 # 开头的属性为私有属性,只能在类内部访问,外部无法直接获取或修改,增强了封装性。

javascript

class User {
  #password = "123456";

  getPassword() {
    return this.#password;
  }
}

const user = new User();
console.log(user.getPassword()); // '123456'
console.log(user.#password);     // SyntaxError: Private field '#password' must be declared in an enclosing class

六、class vs 构造函数(对比)

对比维度构造函数 + 原型链ES6 class
可读性一般,代码分散极高,结构清晰
可维护性一般,手动维护原型较繁琐高,语法封装性好
工程化不适合复杂项目现代框架首选,支持工程化

目前主流框架如 Vue3、React 都广泛采用 class 或类式写法,足以证明其工程化优势。

七、高频面试题

1. ES6 的 class 和 ES5 的构造函数有什么区别?

  • 语法差异:class 语法更简洁,内置方法自动挂载原型。

  • 提升(Hoisting):函数声明会提升,类声明不会,必须先声明后使用。

  • 严格模式:类内部默认是严格模式。

  • 枚举性:类内部方法不可枚举,构造函数原型上的方法默认可枚举。

2. 子类构造函数中为什么要先调用 super()

因为子类的 this 对象需要先通过父类的构造函数进行构建,调用 super() 相当于执行父类的构造函数,否则子类无法获得父类中定义的属性和方法。

3. 如何实现一个不能被实例化的类?

可以通过将构造函数设为私有,或利用静态方法返回实例的方式实现。常见写法是使用 new.target 进行限制。

javascript

class CannotNew {
  constructor() {
    if (new.target === CannotNew) {
      throw new Error("This class cannot be instantiated");
    }
  }
}

4. 私有属性的实现原理是什么?

私有属性通过编译时的语法限制实现,外部无法访问。在运行时,可以通过 WeakMap 或 Symbol 模拟,但 ES2022 原生支持的 # 写法更严格、更安全。

八、总结

  • class 使 JavaScript 的面向对象编程更加规范、易于维护。

  • constructor 负责实例初始化,实例方法自动挂载在原型上。

  • extends 与 super 提供了简洁高效的继承实现。

  • class 本质是语法糖,底层仍基于原型链机制。

  • 支持 getter/setter、静态属性、私有属性等高级特性,满足复杂场景需求。

掌握 class,不仅是掌握 JavaScript 面向对象的标准写法,更是迈向现代工程化开发的关键一步。

下一篇:执行上下文、作用域链与闭包强化

内容概要:本文围绕“基于需求侧响应的配电网供电能力综合评估”展开研究,重点探讨了价格型需求响应机制对配电网供电能力的影响,并提出了一套科学的综合评估方法。研究构建了一个涵盖一次设备安全、负荷平稳性、电能质量和系统效率等多个维度的评价指标体系,采用熵权法客观确定各指标权重,并结合模糊综合评价模型实现双层评分机制,从而定量评估不同运行场景下配电网的承载能力。通过Python编程实现算法仿真,利用算例分析验证了所提模型在不同分布式能源渗透率及多种需求响应策略下的有效性灵敏度,揭示了价格激励措施在提升电网承载力方面的积极作用,为现代配电网的规划、调度运行优化提供了理论依据和技术支撑。; 适合人群:具备一定电力系统基础知识和Python编程能力,从事电力系统规划、运行优化、需求响应等相关领域的科研人员及研究生。; 使用场景及目标:①评估高比例电动汽车、分布式电源接入背景下配电网的实际供电能力;②分析价格型需求响应策略对提升电网承载力的作用效果;③为配电网扩容改造、运行调度和需求管理政策制定提供决策支持; 阅读建议:建议读者结合文中提供的Python代码进行实证复现,重点关注熵权法模糊综合评价的实现逻辑,并尝试修改参数设置以观察评估结果的变化趋势,加深对模型机理的理解。
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 在Qt应用程序开发过程中,有时我们可能需要构建一个具备特殊视觉效果的窗口,例如设计成没有边框但带有阴影,并且依然允许用户拖动窗口。此类需求通常出现在构建简洁用户界面或定制化窗口外观的场景中。标题“Qt(部分)无边框窗口 边框阴影,可以拖动边框,移动窗口”所涵盖的技术要点主要集中于如何在Qt框架内达成这样的功能,尤其是借助winEvent函数的重写来应对特定的Windows平台事件。 让我们深入理解无边框窗口的概念。在Qt环境中,可以通过调整窗口的边框样式来构建无边框窗口。这通常是通过`setWindowFlags()`函数完成的,将`Qt::FramelessWindowHint`标志整合到窗口的标志参数里。例如: ```cpp setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint); ``` 这样一来,窗口将丧失标准的边框和标题栏,但依然维持着窗口管理的基本功能,例如最大化、最小化和关闭操作,前提是你也没有移除这些相关标志。 接下来,为了给无边框窗口增添阴影效果,可以利用Qt的QGraphicsDropShadowEffect类。首先创建一个QGraphicsView对象作为窗口的底层容器,然后在其上放置一个QGraphicsProxyWidget用以展示实际的窗口内容。接着,为QGraphicsView施加阴影效果: ```cpp QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffe...
内容概要:本文系统研究了同步电机构网型变流器在电力系统中的频率稳定特性及其多时间尺度交互机理,基于Simulink搭建高保真仿真模型,深入分析两类电源在动态响应、惯量支撑、频率调节能力等方面的差异耦合关系。研究涵盖不同运行工况下的频率波动响应特性,重点揭示控制延迟、电气机械动态过程之间的时间尺度耦合机制,探讨构网型变流器在高比例新能源接入背景下对传统同步机主导系统的频率稳定性的影响,评估其替代或协同传统同步机的潜力挑战,为未来电力系统的稳定运行控制策略设计提供理论依据和技术支撑。; 适合人群:具备电力系统分析、自动控制理论及新能源并网技术背景的科研人员、高校研究生及电力工程技术人员;熟悉Simulink仿真环境者更佳; 使用场景及目标:①深入理解同步电机构网型变流器在频率响应特性上的本质差异及其相互作用机理;②支撑高电力电子化电网的频率稳定性分析新型控制器设计;③为多类型电源协同控制策略的研发仿真验证提供模型基础分析平台; 阅读建议:建议结合Simulink仿真模型进行同步操作,重点关注不同时间尺度动态过程的建模方法参数敏感性分析,深入探究频率稳定性的内在机理,全面把握构网型控制在提升系统稳定性方面的优势潜在局限。
代码转载自:https://pan.quark.cn/s/db56051ee6da 依据所提供的文档资料,能够归纳出以下“寻求一个字符串中连续出现频率最高的子串”相关的基础知识: ### 一、问题的阐述剖析 #### 1.1 问题背景 在计算机科学领域中,字符串操作是一项普遍且关键的工作。本议题聚焦于给定字符串,识别其中连续出现频率最高的子串。 #### 1.2 问题陈述 假定存在一个输入字符串 `str`,目标在于找出该字符串中出现频率最高的一个或多个连续子串,并统计它们的出现频次。 #### 1.3 输入输出格式 - **输入**:一个字符串 `str`。 - **输出**:连续出现频率最高的子串及其对应的出现次数。 ### 二、算法的构思执行 #### 2.1 基本理念 遍历字符串的所有可能子串,并借助某种数据结构来追踪每个子串的出现频次。通过对比所有子串的出现频次,从而识别出出现频次最高的子串。 #### 2.2 具体执行步骤 1. **初始化**:设定一个字符串 `str` 来存储输入的字符串,以及一个辅助变量 `tep` 来暂存当前子串。 2. **外层循环**:从字符串长度减去1至1的逆向遍历,每次循环的 `i` 代表子串的长度。 3. **内层循环**:从0至字符串长度减去当前子串长度的遍历,每次循环的 `j` 指示子串的起始位置。 4. **子串提取**:运用 `substr` 方法从位置 `j` 开始截取长度为 `i` 的子串并存储至 `tep` 中。 5. **子串检测**:借助 `find` 和 `rfind` 方法分别确定子串在字符串中的初始出现位置 `t` 最终出现位置 `num`。 6. **判定条件**:若 `t` ...
源码下载地址: https://pan.quark.cn/s/a4b39357ea24 在Linux操作系统平台上进行C++语言开发,达成串行通信功能是一项核心且关键的技能,特别是在嵌入式系统设计、设备管理或物联网解决方案中。此"Linux下C++实现简易串口交互"范例展示了一个基础性的架构,旨在协助程序员了解怎样运用C++计算机的串行端口(COM端口)进行互动,完成数据的发送及接收任务。接下来将详尽阐述相关技术要点。 1. **串行通信原理**: 串行通信是一种历史悠久的通信机制,借助串行接口来传输信息。在Linux环境中,串行端口通常被映射为/dev/ttySx的路径,其中x代表端口的编号,例如/dev/ttyS0或/dev/ttyUSB0等。串行通信所涉及的重要参数包含波特率、数据位数、停止位数及校验类型等。 2. **C++系统接口调用**: 若要在C++中操作串口,必须借助系统级调用或第三方库。本范例可能直接运用了包含在<termios.h>头文件中的函数,比如使用tcgetattr()和tcsetattr()来配置串口特性,open()和close()用于串口的开启关闭,以及write()和read()负责数据的发送接收。 3. **<termios.h>中的结构体**: struct termios结构体是控制串口行为的决定性组件,它包含了串口的多种配置选项,如波特率(Baud Rate)、数据位(Data Bits)、停止位(Stop Bits)和校验位(Parity Bit)等。程序员需要通过cfsetispeed()和cfsetospeed()来设定输入和输出的波特率,而c_cflag字段则用于设定其他串口配置。 4. **串口初始化...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我一声阿雷吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值