ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争

在这里插入图片描述

文章目录

  • ES6 类
    • ES6 类的常见特性
      • 1. 构造函数
      • 2. 实例方法
      • 3. 静态方法
      • 4. 继承
  • TypeScript 类
    • TypeScript 类的特性
      • 1. 类型注解
      • 2. 访问修饰符
      • 3. 类型推断
      • 4. 接口实现

ES6 类

ES6(ECMAScript 2015)引入了类的概念,为 JavaScript 增加了面向对象编程的能力。ES6 中的类是一种语法糖,本质上仍然是基于原型的继承。使用类可以定义构造函数、实例方法和静态方法,并且支持继承和类之间的关系。

ES6 类的常见特性

以下是一些 ES6 类的常见特性:

1. 构造函数

类中的构造函数通过 constructor 关键字定义,并且在创建实例时被调用。

当使用 ES6 类创建对象时,构造函数是在实例化过程中自动调用的方法。构造函数使用 constructor 关键字定义在类内部,它负责初始化对象的属性和状态。

以下是一个使用 ES6 的构造函数的示例:

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

const person1 = new Person('Alice', 28);
person1.greet(); // 输出:Hello, my name is Alice and I am 28 years old.

在上面的例子中,我们创建了一个名为 Person 的类。构造函数 constructor 接受两个参数 nameage,并将它们分别赋值给实例属性 this.namethis.agegreet 方法用于打印出个人信息。

通过使用 new 关键字,我们可以实例化该类并传入相应的参数。在实例化过程中,构造函数会被自动调用,初始化属性。然后,我们可以调用 greet 方法来打印出个人信息。

值得注意的是,ES6 类中的构造函数只能有一个,且使用 super 关键字来调用父类的构造函数(如果有继承关系)。构造函数可以执行各种操作,例如初始化数据、调用其他方法或执行其他逻辑,以确保实例在创建时处于正确的状态。

2. 实例方法

类中的实例方法不需要使用关键字 function 声明,直接在类体内声明即可。实例方法默认会绑定到实例对象。

在 ES6 类中,实例方法是定义在类的原型上的方法,可以被类的实例调用。以下是一个使用 ES6 的实例方法的示例:

class Circle {
  constructor(radius) {
    this.radius = radius;
  }

  calculateArea() {
    return Math.PI * this.radius * this.radius;
  }

  calculateCircumference() {
    return 2 * Math.PI * this.radius;
  }
}

const circle1 = new Circle(5);
console.log(circle1.calculateArea()); // 输出:78.53981633974483
console.log(circle1.calculateCircumference()); // 输出:31.41592653589793

在上面的例子中,我们创建了一个名为 Circle 的类。该类有一个构造函数,接受一个参数 radius 并将其赋值给实例属性 this.radius

然后,我们定义了两个实例方法 calculateAreacalculateCircumferencecalculateArea 方法用于计算圆的面积,calculateCircumference 方法用于计算圆的周长。这两个方法都可以通过类的实例进行调用。

使用 new 关键字我们实例化了 Circle 类,并传入半径为 5。然后我们分别调用 calculateAreacalculateCircumference 方法,并打印出结果。

ES6 类中的实例方法是绑定到类的原型上的,这意味着每个类的实例都共享同一个实例方法的实现,从而节省了内存空间。同时,实例方法可以访问类的实例属性和其他实例方法,允许我们在方法内部处理实例的数据和状态。

3. 静态方法

类中的静态方法使用 static 关键字声明,静态方法与实例无关,可以直接通过类来调用。

在 ES6 类中,静态方法是定义在类本身上的方法,而不是类的实例。可以通过类名直接调用静态方法,而不需要创建类的实例。以下是一个使用 ES6 的静态方法的示例:

class MathUtils {
  static add(a, b) {
    return a + b;
  }

  static subtract(a, b) {
    return a - b;
  }
}

console.log(MathUtils.add(5, 3)); // 输出:8
console.log(MathUtils.subtract(10, 4)); // 输出:6

在上面的例子中,我们创建了一个名为 MathUtils 的类。该类定义了两个静态方法 addsubtract。这两个方法都可以直接通过类名进行调用,而不需要创建类的实例。

使用类名 MathUtils 来调用静态方法,并传入相应的参数。然后我们打印出结果。

ES6 类中的静态方法是绑定到类本身的,而不是绑定到类的实例。因此,它们不能访问类的实例属性或其他实例方法。静态方法通常用于执行与类相关的操作,例如辅助函数、工具函数或对象的创建和管理。

可以通过在方法前添加 static 关键字来定义静态方法。静态方法可以通过类名直接调用,而无需实例化对象。这使得静态方法具有更高的灵活性和代码组织性,可以在不创建实例的情况下执行特定的功能。

4. 继承

通过 extends 关键字可以实现类的继承,子类可以继承父类的属性和方法,并可以覆盖或扩展父类的功能。

在 ES6 中,我们可以使用 extends 关键字实现类的继承。通过继承,一个子类可以继承父类的属性和方法,同时可以添加新的属性和方法。以下是一个使用 ES6 实现继承的代码示例:

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

  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  bark() {
    console.log(`${this.name} barks loudly.`);
  }
}

const myDog = new Dog('Max', 'Labrador');
myDog.speak(); // 输出:Max makes a sound.
myDog.bark(); // 输出:Max barks loudly.
console.log(myDog.breed); // 输出:Labrador

在上面的例子中,我们创建了一个名为 Animal 的父类。该类有一个构造函数,接受一个参数 name 并将其赋值给实例属性 this.name。还定义了一个方法 speak,用于输出动物发出声音。

然后,我们创建了一个名为 Dog 的子类,使用 extends 关键字来继承父类 Animal。子类 Dog 有一个构造函数,接受两个参数 namebreed。在子类的构造函数中,我们使用 super 关键字调用父类的构造函数,并传递 name 参数。然后,我们将 breed 参数赋值给子类特有的实例属性 this.breed

子类 Dog 还定义了一个新的方法 bark,用于输出狗的吠声。

通过创建 Dog 类的实例 myDog,我们可以调用继承自父类的方法 speak 和子类自己的方法 bark。还可以访问子类特有的属性 breed

继承允许我们在子类中复用父类的代码和功能,并在子类中添加更多特定的属性和方法。这提高了代码的可重用性和可维护性,并支持面向对象编程的概念,如封装、继承和多态。

TypeScript 类

TypeScript 是一个由 Microsoft 开发的开源编程语言,它是 JavaScript 的一个超集,增加了静态类型检查和面向对象编程的特性。TypeScript 中的类和 ES6 类有相似之处,但又具有更强的类型系统和其他功能。

TypeScript 类的特性

以下是一些 TypeScript 类的特性:

1. 类型注解

TypeScript 强调类型的静态检查,可以在类的属性、方法和参数上添加类型注解,以约束数据类型。

TypeScript 是 JavaScript 的一个超集,它提供了类型注解的功能来静态检查代码。通过类型注解,我们可以为变量、函数参数、函数返回值等添加类型信息,从而使编译器能够检查代码中的类型错误,并在开发过程中提供更好的代码提示和自动补全。

以下是一个使用 TypeScript 的类型注解的代码示例:

function greet(name: string): void {
  console.log(`Hello, ${name}!`);
}

let username: string = "John";
greet(username); // 输出:Hello, John!

在上面的例子中,我们定义了一个名为 greet 的函数。函数接受一个参数 name,并且我们使用 : string 进行类型注解来指定该参数的类型为字符串。

同时,我们还为函数的返回值 void 添加了类型注解,表示该函数没有返回值。

在函数调用时,我们创建一个名为 username 的变量,并将其类型注解为字符串。然后,我们将 username 作为参数传递给 greet 函数。

TypeScript 编译器将根据类型注解进行代码检查,以确保传递给函数的参数类型正确,并且函数的返回值与类型注解一致。

类型注解提供了一种强大的工具,可以增强代码的可读性和可维护性,并提供更好的开发体验。它可以帮助我们在编译阶段发现潜在的类型错误,并减少在运行时出现的错误。此外,类型注解还提供了更好的代码提示和自动补全功能,以提高开发效率。

2. 访问修饰符

TypeScript 提供了 publicprotectedprivate 等访问修饰符,用于控制类成员的访问权限。

TypeScript 提供了访问修饰符来控制类的属性和方法的访问权限。有三种主要的访问修饰符:publicprotectedprivate

下面是一个使用 TypeScript 访问修饰符的示例代码:

class Person {
  public name: string;
  protected age: number;
  private phoneNumber: string;

  constructor(name: string, age: number, phoneNumber: string) {
    this.name = name;
    this.age = age;
    this.phoneNumber = phoneNumber;
  }

  public introduce(): void {
    console.log(`My name is ${this.name}. I am ${this.age} years old.`);
    this.privateMethod();
  }

  protected protectedMethod(): void {
    console.log("This is a protected method.");
  }

  private privateMethod(): void {
    console.log("This is a private method.");
  }
}

class Employee extends Person {
  public position: string;

  constructor(name: string, age: number, phoneNumber: string, position: string) {
    super(name, age, phoneNumber);
    this.position = position;
  }

  public getPhoneNumber(): void {
    console.log(`${this.name}'s phone number is ${this.phoneNumber}.`);
    this.protectedMethod();
  }
}

const john = new Person("John", 30, "123456789");
console.log(john.name); // 公有属性,可以访问
// console.log(john.age); // 受保护属性,不能在类外部访问
// console.log(john.phoneNumber); // 私有属性,不能在类外部访问
john.introduce(); // 公有方法,可以访问

const employee = new Employee("Bob", 25, "987654321", "Manager");
// console.log(employee.name); // 公有属性,可以访问
// console.log(employee.age); // 受保护属性,不能在类外部访问
// console.log(employee.phoneNumber); // 私有属性,不能在类外部访问
employee.introduce(); // 公有方法,可以访问
employee.getPhoneNumber(); // 子类可以访问受保护方法

在上面的示例中,我们创建了一个名为 Person 的基类,并定义了三个属性:nameagephoneNumbername 是公有属性,可以在类外部访问;age 是受保护属性,只能在类内部及其子类中访问;phoneNumber 是私有属性,只能在类内部访问。

我们还定义了两个方法:introduceprotectedMethodprivateMethodintroduce 是公有方法,可以在类外部调用;protectedMethod 是受保护方法,只能在类内部及其子类中调用;privateMethod 是私有方法,只能在类内部调用。

然后,我们创建了一个名为 Employee 的子类,继承自 Person。子类拥有 position 属性,并在构造函数中通过 super 关键字调用父类的构造函数来初始化继承的属性。

通过创建 PersonEmployee 的实例,我们可以看到不同访问修饰符的效果。只有公有属性和方法可以从类外部访问,受保护属性和方法只能在类内部及其子类中访问,而私有属性和方法只能在类内部访问。

访问修饰符允许我们控制类的成员的可见性和可访问性,并提供了一种封装数据和行为的方式,增强了代码的安全性和可维护性。

3. 类型推断

TypeScript 可以根据赋值表达式的右侧推断出变量的类型,减少重复的类型注解。

TypeScript 提供了类型推断的功能,能够根据赋值表达式的右侧值自动推断变量的类型。下面是一个使用 TypeScript 类型推断的示例代码:

let name = "Alice"; // 类型推断为 string
let age = 30; // 类型推断为 number
let isStudent = true; // 类型推断为 boolean

let fruits = ["apple", "banana", "orange"]; // 类型推断为 string[]
let numbers = [1, 2, 3]; // 类型推断为 number[]
let matrix = [[1, 2], [3, 4]]; // 类型推断为 number[][]

let person = {
  name: "Bob",
  age: 25,
}; // 类型推断为 { name: string, age: number }

function add(a: number, b: number) {
  return a + b;
} // 函数参数和返回值的类型推断为 number

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
} // 类的属性和构造函数参数的类型推断为 string

let animal = new Animal("Dog"); // 类的实例类型推断为 Animal

在上述示例中,我们声明了一些变量并初始化它们,TypeScript 根据赋值的值来推断变量的类型。例如,通过字符串赋值给变量 name,TypeScript 推断出 name 的类型为 string

类似地,数组的元素类型也可以通过初始化的值进行推断。在示例中,fruits 的类型被推断为 string[],即字符串数组。

在函数定义中,参数 ab 的类型被推断为 number,因为我们在函数体内使用了加法操作,而返回值的类型也被推断为 number

对于类,属性和构造函数参数的类型也可以通过初始化来推断。在示例中,Animal 类的属性 name 和构造函数参数 name 都被推断为 string 类型。

最后,当我们创建 Animal 类的实例 animal 时,TypeScript 推断出它的类型为 Animal

类型推断是 TypeScript 的一个强大功能,能够减少显式类型注解的冗余,并帮助开发人员更轻松地编写类型安全的代码。

4. 接口实现

TypeScript 支持类实现接口,通过 implements 关键字来强制类遵循接口的契约。

在 TypeScript 中,接口(Interfaces)用于定义对象的结构和类型。一个类可以通过实现(implements)一个接口来强制遵循该接口所定义的结构。下面是一个使用 TypeScript 接口实现的示例代码:

interface Shape {
  getArea(): number;
}

class Circle implements Shape {
  radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle implements Shape {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  getArea(): number {
    return this.width * this.height;
  }
}

const circle = new Circle(5);
console.log(circle.getArea()); // 输出: 78.53981633974483

const rectangle = new Rectangle(4, 6);
console.log(rectangle.getArea()); // 输出: 24

在上述示例中,我们定义了一个名为 Shape 的接口,它有一个名为 getArea 的方法,返回类型为 number

然后我们创建了两个类 CircleRectangle,它们分别实现了 Shape 接口。这意味着这两个类必须实现 Shape 接口中定义的方法 getArea

Circle 类有一个属性 radius,并在构造函数中初始化。它实现了 getArea 方法来计算圆的面积。

Rectangle 类有两个属性 widthheight,并在构造函数中初始化。它同样实现了 getArea 方法来计算矩形的面积。

通过创建 CircleRectangle 类的实例,并调用它们的 getArea 方法,我们可以得到圆和矩形的面积。

接口的使用使得我们能够在 TypeScript 中定义和强制对象的结构,并确保类遵循指定的接口约束。这提高了代码的可读性和可维护性,并加强了类型检查和类型安全性。

总结来说,ES6 类是 JavaScript 中基于原型的面向对象编程的语法糖,而 TypeScript 类在此基础上增加了强类型检查和其他面向对象编程的特性,使得代码更具可读性、可维护性和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/38448.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【2023 年第二届钉钉杯大学生大数据挑战赛】 初赛 B:美国纽约公共自行车使用量预测分析 问题一Python代码分析

2023 年第二届钉钉杯大学生大数据挑战赛 初赛 B:美国纽约公共自行车使用量预测分析 问题一 1 题目 Citi Bike是纽约市在2013年启动的一项自行车共享出行计划,由“花旗银行”(Citi Bank)赞助并取名为“花旗单车”(Citi Bike)。在曼哈顿,布鲁克…

PDF在线转PPT,不用下载软件网页在线即可转换!

PDF是我们经常在办公中使用的文件格式,它的兼容性和安全性使得它成为了传输文件的首选。而PPT则是我们常用的演示文稿格式,无论是在学校还是在公司,我们都需要制作演讲和汇报的PPT文件。由于这两种文件格式的重要性,我们经常需要进…

Vue+axios 使用CancelToken多次发送请求取消前面所有正在pendding的请求

需求: 项目中 折线图数据是循环调用的,此时勾选一个设备, 会出现多条线。 原因 折线图数据一进来接口循环在调用,勾选设备时,循环调用的接口有的处于pedding状态 ,有的还在加载中,这就导致勾…

第三方电容笔支持随手写吗?ipad平板可以用的手写笔推荐

我是一位数码爱好者,所以我对电容笔也有一定的了解。我认为,原装的苹果电容笔和一般的电容笔的区别在于它们产生的压感效果不同。由于苹果电容笔拥有着独特的“重力压感”,使我们能够快速地在画面中填充颜色。除此之外,苹果的电容…

ME GO小车

ME GO小车 ⚫ 体积小巧 ⚫ 集成多种传感器和执行器 ⚫ Mixly图形化编程 避障检测、自动巡线、灯光显示、 声音报警、自动测距、物联遥控等 ME GO小车——俯视图 ME GO小车——车底 ME GO CE 以上选自芯”向未来 元控智联挑战赛(小学组)赛事介绍资料二…

操作系统进行设备控制的方式

一.I/O控制方式 上一篇的博客介绍了设备管理的一些概念基础知识点,其中I/O控制方式这一块没有详细说明。设备管理的主要任务之一是控制设备和内存或CPU之间的数据传送。外围设备和内存之间的输入/输出控制方式有4种,下面分别加以介绍。 二.程序直接控制…

pandas常用方法

一、提要 pandas对于处理表格类数据来说是非常方便的模块,同时也是做数据分析绕不开的第三方库。这里将工作中常用到的各种处理方法记录下来二、常用方法 接下来的以 df 表示我们要处理的 dataframe 表格数据 1、取值 # 循环遍历取值 for i in range(len(df)):y…

吴恩达机器学习2022-Jupyter-Scikit-Learn教学

1可选实验室: 线性回归使用 Scikit-Learn 有一个开源的、商业上可用的机器学习工具包,叫做 scikit-learn。本工具包包含您将在本课程中使用的许多算法的实现。 1.1目标 在这个实验室里: 利用 scikit-学习使用线性回归梯度下降法来实现 1.2工具 您将利用 sciki…

自动化用例编写思路 (使用pytest编写一个测试脚本)

目录 一,明确测试对象 二,编写测试用例 构造请求数据 封装测试代码 断言设置 三,执行脚本获取测试结果 四,总结 经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口…

postgreSQL数据库的安装

文章目录 一、Linux 下安装 postgreSQL 数据库1.1、准备环境1.2、关闭防火墙跟SELinux1.2.1、关闭防火墙 firewalld1.2.2、关闭SELinux 1.3、挂载本地镜像1.4、软件包的下载postgreSQL 一、Linux 下安装 postgreSQL 数据库 1.1、准备环境 操作系统IP应用Red Hat 8192.168.192…

ConfigMap 补充 和 Secret

对于上一篇文章我们分享了为什么要使用 ConfigMap ,我们创建 ConfigMap 的时候可以传入单个或者多个键值对,也可以传入文件,还分享了如何简单的传入 ConfigMap 里面的数据作为环境变量 我们补充一下使用 ConfigMap 一次性传递多个条目吧 一…

【监控系统】Prometheus监控组件Node-Exporter配置实战

这一节,我们来配置一下Node-Exporter,那么我们先来了解一下什么是Prometheus的Exporter? 任何向Prometheus提供监控样本数据的程序都可以被称为一个Exporter,它是一种用于将不同数据源的指标提供给Prometheus进行收集和监控的工具…

缓存淘汰策略

LRU 与 LFU 缓存策略及其实现。 应用层缓存 鉴于磁盘和内存读写的差异性,DB 中低频写、高频读的数据适合放入内存中,直接供应用层读写。在项目中读取用户资料时就使用到了 LRU,而非放到 Redis 中。 缓存的 2 个基本实现 Set(key string, v…

ios 通过xib自定义控件

通过xib自定义控件 xib和stroyboayd对比 共同点: 都是用来描述软件界面 都是用interface Builder工具来编辑 本质都是转换成代码去创建控件 不同点: xib是轻量级的,用来描述局部ui界面 创建模型文件 XMGCar 自定义控件 xib 图形设计 …

mac批量提取图片文件名到excel?

mac批量提取图片文件名到excel?最近有个小伙伴向我求助一个电脑操作上的问题,问我在Mac电脑上用什么方法可以快速批量的将大量图片的名称一次性提取出来,并且保存到excel表格里。记得小编曾经给大家分享过windows电脑上批量提取文件名称的方法…

爱心代码李峋同款爱心 python html

目录 前言 一、python 1.python 第一个 2.python第二个 二、HTML 1.第一个 2.第二个html 3.第三个html 3.第四个html 总结 前言 最近那个电视剧很火,就是搞爱心代码的,本人兴趣使然,在网上搜集了一些代码,经过一定修改&…

【iOS】—— 编译链接

【iOS】—— 编译链接 文章目录 【iOS】—— 编译链接编译流程预处理(预编译Prepressing)编译(Compilation)汇编(Assembly)链接(Linking) 编译流程 编译流程分为四步 预处理&#…

python 安装、配置、使用 xlrd模块、numpy模块

目录 一、xlrd模块 (一)安装xlrd模块 (二) pycharm 配置xlrd (三) 读取xls格式 (四)xlrd读取时间日期时,会是float类型,需要转换。 二、numpy模块 (一)n…

基于linux下的高并发服务器开发(第一章)- Linux系统IO函数

05 / Linux系统IO函数 (1)man 2 open >>打开一个已经存在的文件 int open(const char *pathname, int flags); 参数: pathname:要打开文件路径 - flags:对文件的操作权限设置还有其他的设置 O_RDONLY,O_WRONLY,O_RDWR 这三个设置是互斥…