You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
一个经典的例子,电脑的 USB 接口,我们可以插上鼠标、键盘、U 盘等设备,来为其扩展不同的功能,每个设备的功能是不同的,但是 USB 接口的规范遵守的是统一的,这也就是我们所讲的多态性,通过声明抽象类或接口定义规范,子类重写和父类名称相同的方法,实现自己的功能。
// 定义USB 接口规范interfaceUSB{run(): void;}// 实现一个 USB 规范的键盘设备classUKeyimplementsUSB{run(): void{console.log('USB 规范的键盘设备');}}// 实现一个 USB U 盘设备classUDiskimplementsUSB{run(): void{console.log('USB 规范的 U 盘设备');}}// 计算机类classComputer{useUSB(usb: USB){usb.run();}}constcomputer=newComputer();computer.useUSB(newUKey());// USB 规范的键盘设备computer.useUSB(newUDisk());// USB 规范的 U 盘设备
在 JavaScript 中 ES6 之前我们使用函数(构造器函数)和基于原型来创建一个自定义的类,但这种方式总会让人产生困惑,特别是习惯了 Java、PHP 等面向对象编程的同学来说更加难以理解。
抽象一个类
面向对象编程的基本单位是对象,但对象又是由类实例化的,所以我们第一步需要先知道怎么去声明一个类。
类的声明
类的声明使用 class 关键词,类名与变量、函数等命名规则类似,这里要首写字母大写,类名后跟上一对花括号可以理解为的类的主体,类的主体三部分组成:成员属性、构造函数、成员方法。
成员属性
在类中可以直接声明变量,也称为成员属性,另外在类中声明成员属性我们还可以使用关键词 private、public、protected 来修饰:
构造函数
构造函数用于类的初始化,可以声明哪些字段是必传的,哪些字段是非必传的。
构造函数参数中
public name: string
相当于如下形式:在构造函数内部,可以为之前声明的成员属性做赋值。
成员方法
在类中直接声明函数称为成员方法,注意这里的函数是不需要加 function 关键词的,成员方法要和对象有关联,例如 eat 方法(每个都需要吃饭的),另外方法也可以使用 public、private、protected 等关键词声明。
什么是对象?只要能用属性、方法描述的事物我们都可以声明为一个类,然后对这个类实例化出对象使用。
类的实例化对象
上面我们抽象了一个类 Person,但是在程序中我们不是直接使用的类,而是通过抽象出来的类来实例化一个或多个对象为我们所使用。
实例化一个对象主要使用 new 关键词,后面跟上需要实例的类。
static 静态属性
static 可以用来将类成员属性、成员方法标识为静态的。
static 关键词修饰的类成员属性、成员方法是属于类的与类实例对象无关,且在多个对象之间是共享的。
下例定义了静态属性 language 为 chinese,最后实例化了两个对象,其中 language 可以使用类名来调用,且在两个对象间是共享的。
面向对象编程 — 封装性
对象的成员属性或方法如果没有被封装,实例化后在外部就可通过引用获取,对于用户 phone 这种数据,是不能随意被别人获取的。
封装性做为面向对象编程重要特性之一,它是把类内部成员属性、成员方法统一保护起来,只保留有限的接口与外部进行联系,尽可能屏蔽对象的内部细节,防止外部随意修改内部数据,保证数据的安全性。
Private 关键词修饰
用 private 关键词修饰类的成员属性和成员方法来实现对成员的封装,封装后的成员对象仅能在类的内部被访问。
下面我们使用 private 关键词对 Person 类部分成员进行封装,能够被外部访问的只有 info 方法。
私有成员访问
使用 private 修饰过后的成员属性或方法在外部将会无法访问,如果需要访问,我们可以设置公有方法返回私有属性,这里你也可以做一些条件限制。
面向对象编程 — 继承性
已存在的用来派生新类的类成为基类,又可称为超类。新派生的类称为派生类或子类。
在 C++ 中一个派生类可以继承多个基类,有单继承、多继承。在 TypeScript、Java、PHP 中都是只可继承自一个基类,只有单继承。
下图展示一个关于 Person 基类被继承的示意图:
子类继承应用
创建基类 Person 一个成员属性 name,一个成员方法 eat。
创建派生类 Student,通过关键词 extends 继承于基类 Person,实现一个自定义的 study 方法。
创建派生类 Work,通过关键词 extends 继承于基类 Person,实现一个自定义的 work 方法。
上面创建的两个子类 Student、Work 都有自己单独的方法,学生要学习,工人要工作,但是在开始之前都要先吃饱饭吧。
下面我们测试下这个实例。
子类重载父类的方法
我们不能定义重名的函数,也无法在同一个类中定义重名的方法,但是在派生类中我们可以重写在基类中同名的方法。
注意:如果派生类中写了 constructor() 方法,必须在 this 之前调用 super 方法,它会调用基类的构造函数。
接口继承
接口多继承实现
上面讲了在 TS 中类之间只能实现单继承,但是在接口里是可以实现单继承和多继承的。
接口继承类
接口可以通过 extends 关键词继承一个类,如果类成员包含实现,则不会被继承其实现。
面向对象编程 — 多态性
多态性是面向对象编程的三大特性之一,可以让具有继承关系的不同类对象,使用相同的函数名完成不同的功能,通俗的讲:一个子类可以修改、重写父类中定义的相同名称的方法,父类可以使用抽象类或接口来定义相应的规范。
抽象类
抽象类是一种特殊的类,使用 abstract 关键词修饰,一般不会直接被实例化。
抽象类中的成员属性或方法如果没有用 abstract 关键词修饰,可以包含实现细节。如果使用 abstract 关键词修饰,则只能定义,实现必须要在派生类中去做。
接口
接口是一种特殊的抽象类,与之抽象类不同的是,接口没有具体的实现,只有定义,通过 interface 关键词声明。
在继承的时候说过,TypeScript 中只能单继承,但是在接口这里,是可以实现多个接口的。
以下是一个接口的示例:
多态性的应用
一个经典的例子,电脑的 USB 接口,我们可以插上鼠标、键盘、U 盘等设备,来为其扩展不同的功能,每个设备的功能是不同的,但是 USB 接口的规范遵守的是统一的,这也就是我们所讲的多态性,通过声明抽象类或接口定义规范,子类重写和父类名称相同的方法,实现自己的功能。
总结
大学期间自学了 PHP 开发,当时印象比较深刻的一本书是 “细说 PHP”,书中的面向对象这节印象还是比较深刻的,讲的很好,在学习 TypeScript 面向对象的封装、继承、多态特性时很多概念都是相通的,对于理解给予了很大帮助。
Reference
The text was updated successfully, but these errors were encountered: