TypeScript中的类

目录
  • 1.概述
  • 2.定义一个简单的类
  • 3.继承
  • 4.public、private、protected修饰符
    • 4.1getters与setters
  • 5.readonly修饰符
  • 6.静态成员
  • 7.抽象类
  • 8.类与接口

1.概述

类这个概念基本是所有面向对象编程语言都具有一个概念,例如JavaPython等;在JavaScript中ES6 之前是没有类这个概念的,对于熟悉面向对象来程序猿来说有些棘手,因为他们用的都是基于类的继承,对象也是通过类创建出来的。在ES6中添加了类这个概念,虽然只是一个语法糖,但是这就可以让程序员基于类去进行操作了。在TS中也是支持类这个概念的。

2.定义一个简单的类

在TS中也是使用class关键字来定义一个类,示例代码如下:

;(function () {
  // 定义类
  class Person {
    // 公共属性,默认可以不写
    public name: string
    // 构造函数
    constructor(name: string) {
      // 初始化name属性
      this.name = name
    }
  }
  // 实例化类
  const person = new Person('一碗周')
  console.log(person.name) // 一碗周
})()

上面定义的那个类中具有一个构造函数和一个公共属性name,在类实例化时调用了constructor构造函数,调用对功能属性进行初始化。

上面的写法还有一种简写形式,如下所示:

;(function () {
  class Person {
    constructor(public name: string) {}
  }
  // 实例化类
  const person = new Person('一碗周')
  console.log(person.name) // 一碗周
})()

这个写法等同于上面那个写法。

3.继承

在面向对象的编程语言中,有一个重要得特征就是继承。继承就是基于某个类来扩展现有的类。

例如,爸爸在北京有一个四合院,儿子可以继承爸爸的四合院,而且还可以自己去买一栋别墅;最终儿子的房产拥有北京的四合院和一栋别墅。

在TS中继承使用extends关键字,示例代码如下:

;(function () {
  // 定义一个基类,又称超类
  class Person {
    // 在基类中定义一个name属性
    constructor(public name: string) {}
  }
  // 定义一个派生类,又称子类,继承于基类
  class Programmer extends Person {
    constructor(name: string, public hobby: string) {
      // 通过 super 调用基类的构造函数
      super(name)
    }
  }
  // 实例化子类
  const programmer = new Programmer('一碗周', 'coding')
  console.log(programmer.name, programmer.hobby) // 一碗周 coding
})()

如上示例代码中,Person称作基类 ,或者称超类 ,Programmer是一个派生类 ,或者称子类 。

在上面那个例子中,Programmer类通过extends关键字继承于Person类。子类拥有父类全部的属性和方法。

在子类的构造函数中,我们必须调用super()方法来执行基类的构造函数,这个是必须的。

类的继承不仅可以继承类,而且还可以在子类重写父类的属性或者方法。实例代码如下:

// 定义一个 Person类
class Person {
    constructor(public name: string) {}
    // 定义一个方法
    sayMy() {
        console.log(`我的名字: ${this.name}`)
    }
}
// 定义一个 Adult 类继承于 Person 类
class Adult extends Person {
    constructor(public age: number) {
        super('彼岸繁華')
    } // 重写父类方法
    sayMy() {
        console.log(`我的名字: ${this.name} 年龄: ${this.age}`)
    }
}
// 定义一个 Programmer 类继承于 Adult 类
class Programmer extends Adult {
    constructor(public hobby: string) {
        super(18)
    } // 重写父类方法
    sayMy() {
        console.log(
            `我的名字: ${this.name} 年龄: ${this.age} 爱好: ${this.hobby}`
        )
    }
}
// 类的实例化
const programmer = new Programmer('coding')
programmer.sayMy() // 我的名字: 彼岸繁華 年龄: 18 爱好: coding

首先我们定义了一个Person类,在类中定义了一个属性和一个方法;然后又定义了一个Adult类,这个类继承于Person类,并重写了Person类中的方法;最后又定义了一个Programmer类,这个类继承于Adult类,并重写了Adult类中的方法,也就是说Programmer类拥有Person类与Adult类中的全部属性与方法,但是sayMe()方法被重写了两次,也就是说Programmer类拥有3个属性和1个方法。

4.public、private、protected修饰符

public、private、protected修饰符的区别:

  • public:公开的,我们可以在类中自由的访问类中定义的成员。TS默认为public
  • private:私有的,仅仅可以在类中访问定义的成员,在类外访问不到
  • protected:受保护的,可以在本类或者子类中访问定义的成员。

示例代码如下所示:

// 定义一个 Person 类,其中包含 public 成员 private 成员和 protected 成员。
class Person {
  public name: string
  // 约定 私有成员一般采用 _ 开头
  private _age: number
  protected hobby: string
  // 属性初始化
  constructor(name: string, age: number, hobby: string) {
    this.name = name
    this._age = age
    this.hobby = hobby
  }
  sayMy() {
    console.log(this.name, this._age, this.hobby)
  }
}

// 实例化 Person 类
const person = new Person('一碗周', 18, 'coding')

console.log(person.name) // 一碗周
// 类外访问私有成员 抛出异常
// console.log(person._age) // 报错
// 类外访问保护成员 抛出异常
// console.log(person.hobby) // 报错

// private 成员和 protected 成员可以在类内访问
person.sayMy() // 一碗周 18 coding

// 定义一个类继承与 Person 类
class Programmer extends Person {
  constructor(name: string, age: number, hobby: string) {
    super(name, age, hobby)
  }
  sayMy() {
    console.log(this.name) // 一碗周
    // 在子类不可以访问父类的私有成员
    // console.log(this._age) // 报错
    // 在子类可以访问受保护的成员
    console.log(this.hobby) // coding
  }
}

// 实例化 Programmer 类
const programmer = new Programmer('一碗周', 18, 'coding')
programmer.sayMy()

// 确保跟其他代码中的成员冲突
export {}

如上代码中,我们可以在基类中访问,公共成员、私有成员和保护成员,但是我们在类外只能访问公共成员。当我们定义一个子类继承于Person类时,我们可以在子类访保护成员,但是不能访问私有成员。

4.1getters与setters

类中的私有成员和保护成员我们并不是真的不能读写,在TS中提供了getterssetters帮助我们有效的控制对对象成员的访问。

示例代码如下所示:

// 定义一个 Person 类
class Person {
  // 约定 私有成员一般采用 _ 开头
  private _name: string
  // 属性初始化
  constructor(name: string) {
    this._name = name
  }
  // 获取 私有的 _name 属性值
  get getName(): string {
    return this._name
  }
  // 设置 私有的 _name 属性值
  set setName(name: string) {
    this._name = name
  }
}
// 实例化类
const person = new Person('一碗粥')
// 通过 getName 的方式获取
console.log(person.getName) // 一碗粥
// 通过 setName 的方式设置 _name 的值
person.setName = '一碗周'
// 重新获取
console.log(person.getName) // 一碗周

5.readonly修饰符

我们可以通过 readonly修饰符将一个属性设置为只读的。只读属性必须在声明时或者在构造函数中进行初始化。

示例代码如下所示:

// 定义一个类,且具有一个只读属性
class Person {
  // readonly name: string
  // 等同于
  // public readonly name: string
  // constructor(name: string) {
  //     this.name = name
  // }
  // 或者
  constructor(public readonly name: string) {}
}
// 实例化
const person = new Person('一碗周')
console.log(person.name) // 一碗周
// 修改name的值
// person.name = '一碗周' // 错误! name 是只读的.

6.静态成员

在 TS 中我们也可以创建静态成员,这些属性或者方法是存在于类本身而不是存在于类的实例上。在 TS中定义静态成员与ES6中一样,都是使用static关键字来说明。

示例代码如下所示:

class Hero {
  // 计数器
  static count = 0
  constructor(public name: string) {
    // 每创建一个属性 count ++
    ++Hero.count
  }
}
// 实例一个 Hero 类
const hero1 = new Hero('孙悟空')
console.log(Hero.count) // 1
const hero2 = new Hero('哪吒')
console.log(Hero.count) // 2

这里我们用静态属性实现了一个记录实例化几个类的一个计数器。

7.抽象类

想要理解什么是抽象类,就需要先理解什么是抽象,所谓的抽象就是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征 。例如苹果、香蕉、生梨、葡萄、桃子等,它们共同的特性就是水果。得出水果概念的过程,就是一个抽象的过程。

抽象类就是将众多类中具有共同部分的功能抽离出来,单独创建一个类作为其他派生类的基类使用。他们不允许被实例化,定义抽象类使用abstract关键字。

抽象方法就是只有方法的定义,没有方法体,方法体需要在子类中进行实现。

示例代码如下:

// 通过 abstract 关键字 定义一个抽象类,该类不必进行初始化,仅作为基类使用
abstract class Department {
  // 初始化name成员,参数属性
  constructor(public name: string) {}

  printName(): void {
    console.log('部门名称: ' + this.name)
  }
  // 抽象方法必须包含 abstract 关键字
  abstract printMeeting(): void // 必须在派生类中实现
}

class AccountingDepartment extends Department {
  constructor() {
    super('会计部') // 在派生类的构造函数中必须调用super()
  }

  printMeeting(): void {
    console.log('会计部是负责管钱的部门')
  }
}

// const department = new Department() // 抛出异常:不能创建一个抽象类的实例
// 实例化抽象子类
const department = new AccountingDepartment()
// 调用抽象类中的方法
department.printName() // 部门名称: 会计部
// 调用在派生类实现的抽象方法
department.printMeeting() // 会计部是负责管钱的部门

8.类与接口

类定义会创建两个东西:类的实例类型和一个构造函数,因为类可以创建出类型,这一点与我们之前学习的接口类似,所以说我们可以在使用接口的地方使用类。

示例代码如下所示:

// 定义一个类
class Point {
    x: number
    y: number
}
// 定义一个接口继承与类
interface Point3d extends Point {
    z: number
}

let point3d: Point3d = { x: 1, y: 2, z: 3 }

类可以通过implement去实现一个接口,示例代码如下:

// 定义接口
interface Eat {
  eat(food: string): void
}
interface Run {
  run(distance: number): void
}

// 定义类实现接口
class Person implements Eat, Run {
  eat(food: string): void {
    console.log(food)
  }
  run(distance: number) {
    console.log(distance)
  }
}
export {}

到此这篇关于TypeScript中的类的文章就介绍到这了,更多相关TypeScript类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解TypeScript中的类型保护

    概述 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 layEggs(); } interface Fish { // 独有方法 swim(); // 共有方法 layEggs(); } function getSmallPet(): Fish | Bird { // ... } let pet = getSmallPet(); pet.layEggs(); // 正常 pet.swim();

  • 详解 TypeScript 枚举类型

    目录 1. 数字枚举 2. 字符串枚举 3. 反向映射 4. 异构枚举 5. 常量枚举 6. 枚举成员类型和联合枚举类型 (1)枚举成员类型 (2)联合枚举类型 7. 枚举合并 前言: TypeScript 在 ES 原有类型基础上加入枚举类型,使得在 TypeScript 中也可以给一组数值赋予名字,这样对开发者比较友好,可以理解枚举就是一个字典. 枚举类型使用enum来定义: enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, F

  • TypeScript枚举类型

    目录 1.概述 2.数字枚举 2.1反向映射 3.字符串枚举 4.const枚举 5.总结 1.概述 所谓的枚举类型就是为一组数值赋予名字. enum类型在C++.Java语言中比较常见,TypeScript在JavaScript原有的类型基础上也增加了enum类型. 比如我们需要定义一组角色,需要使用数字表示,就可以使用如下代码定位: enum role{ STUDENT, TEACHER, ADMIN } 上面代码中我们定义了role为一个枚举类型,这个里面有是三个值,TypeScript会

  • 浅谈TypeScript的类型保护机制

    在编写 TS 时,它做了比我们看到的更多的事情,例如类型保护机制.让我们编写的代码更加严谨,至于怎么回事,让我们来看看吧. 由于这些机制的存在,就算你仍旧以 JS 原生的书写方式,也能帮助你提前发现代码中潜在的问题.(对于认为 TS 语句更复杂的人,也能实现 0 门槛,不改变已有的习惯也能享受静态检测的好处.) 类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域内的类型. 为了更简单的理解,我们首先声明一个联合类型用于举例: interface Bird { fly(): any; l

  • 如何在Vue项目中应用TypeScript类

    目录 一.前言 二.使用 1.@Component 2.compued.data.methods 3.@props 4.@watch 5.@emit 三 .总结 一.前言 TypeScript是基于vue-class-component库而来,这个库vue官方推出的一个支持使用class方式来开发vue单文件组件的库 主要的功能如下: methods 可以直接声明为类的成员方法 计算属性可以被声明为类的属性访问器 初始化的 data 可以被声明为类属性 data.render 以及所有的 Vue

  • TypeScript基础类型介绍

    目录 1.基础类型 2.对象类型 2.1数组 2.2元组 2.3对象 3.类型推断 3.1类型联合中的类型推断 3.2上下文类型 4.类型断言 TS 的静态类型可以人为的分为两类: 基础类型:像布尔值(boolean).数字(number).字符串(string).Any(任意类型).Void(无类型).Null. Undefined.Never(无值类型) 对象类型:像数组.函数.对象.枚举.元组. 1.基础类型 TS的类型定义主要通过以下示例代码中演示的方式进行定义: ;(function

  • TypeScript中的类

    目录 1.概述 2.定义一个简单的类 3.继承 4.public.private.protected修饰符 4.1getters与setters 5.readonly修饰符 6.静态成员 7.抽象类 8.类与接口 1.概述 类这个概念基本是所有面向对象编程语言都具有一个概念,例如Java.Python等:在JavaScript中ES6 之前是没有类这个概念的,对于熟悉面向对象来程序猿来说有些棘手,因为他们用的都是基于类的继承,对象也是通过类创建出来的.在ES6中添加了类这个概念,虽然只是一个语法

  • 简单了解TypeScript中如何继承 Error 类

    前言 在JavaScript 中很多时候都需要自定义错误,尤其是开发 Node.js 应用的时候. 比如一个典型的网站服务器可能需要有 NetworkError, DatabaseError, UnauthorizedError 等. 我们希望这些类都拥有 Error 的特性:有错误消息.有调用栈.有方便打印的 toString 等. 最直观的实现方式便是 继承 Error 类. 但考虑 TypeScript 需要编译到 ES5 兼容性问题会较为复杂, 本文用来帮助理解 TypeScript 中

  • TypeScript中的函数和类你了解吗

    目录 函数 作为参数 定义函数 函数参数的类型 可选类型 参数默认值 剩余参数 this的默认推导 函数重载 类 初始化 继承 多态 成员修饰符 总结 函数 以下声明了一个函数类型,通过type来定义类型别名,void 表示没有返回值 type fnType = () => void; 作为参数 函数可以作为参数,传递到另一个函数中 type fnType = () => void; function foo(fn: fnType) { fn(); } function bar() { con

  • TypeScript 中接口详解

    在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScript 的时候,所有的接口都会被擦除掉,因为 JavaScript 中并没有接口这一概念. 先看看一个简单的例子: function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel

  • 深入理解JavaScript和TypeScript中的class

    前言 对于一个前端开发者来说,很少用到 class ,因为在 JavaScript 中更多的是 函数式 编程,抬手就是一个 function,几乎不见 class 或 new 的踪影.所以 设计模式 也是大多数前端开发者的一个短板. 最近在学习 Angular的过程中发现其大量的运用了 class,不得不佩服,Angular 确实是一个优秀的.值得深入研究的 框架. 本文将简单的介绍一下 JavaScript 和 TypeScript 中的 class. 基本概念 在介绍 class 之前,要先

  • TypeScript中使用getElementXXX()的示例代码

    简述 Angular 1.x版本是用JavaScript编写的,我们在百度Angular经常会搜索到AngularJS,并不是JavaScript的什么衍生版本,就是Angular 1.x.在后续版本中,改用TypeScript来重写了Angular框架.改动较大,所以做了个区分,Angular v1.x就叫AngularJS,v2及后续版本统称为Angular. 查资料和解决方案的时候,经常会搜索到大量的AngularJS内容,注意区分. 在这里提一下Angular的历史,是因为本文是在使用这

  • 在 Typescript 中使用可被复用的 Vue Mixin功能

    转到用 Typescript 写 Vue 应用以后,经过一轮工具链和依赖的洗礼,总算蹒跚地能走起来了,不过有一个很常用的功能 mixin,似乎还没有官方的解决方案. 既想享受 mixin 的灵活和方便,又想收获 ts 的类型系统带来的安全保障和开发时使用 IntelliSense 的顺滑体验. vuejs 官方组织里有一个 'vue-class-component' 以及连带推荐的 'vue-property-decorator',都没有相应实现.翻了下前者的 issue,有一条挂了好些时间的待

  • TypeScript中正确使用interface和type的方法实例

    目录 前言 interface type 附:interface和type不同点 总结 前言 interface 和 type 都是用来定义类型,可以理解定义 shape ,那么 shape 表示一种设计大框,或者说只要具有某些特征或者行为就是为一类事物.在有些面向例如 Java 语言中,interface 用于定义行为,如果一个类实现了某一个 interface 表示该类具有某种行为或者说具有某种能力,例如writable 或者 readable .可以通过行为来对事物进行划分.interfa

  • TypeScript中函数重载写法

    目录 1. 函数签名 2.函数重载 2.1 重载签名是可调用的 2.1 实现签名必须是通用的 3.方法重载 4. 何时使用函数重载 5.总结 前言: 大多数函数接受一组固定的参数.但有些函数可以接受可变数量的参数,不同类型的参数,甚至可以根据你调用函数的方式返回不同的类型.为了注释这样的函数,TypeScript 提供了函数重载功能. 1. 函数签名 我们先来考虑一个函数,它返回给一个特定的人的问候信息. function greet(person: string): string { retu

随机推荐