类和接口的相关概念
在面向对象语言中,接口(Interfaces)是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
- 类(Class):定义了一件事物的抽象特点,包含它的属性和方法
- 对象(Object):类的实例,通过
new生成 - 面向对象(OOP)的三大特性:封装、继承、多态
- 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
- 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
- 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如
Cat和Dog都继承自Animal,但是分别实现了自己的eat方法。此时针对某一个实例,我们无需了解它是Cat还是Dog,就可以直接调用eat方法,程序会自动判断出来应该如何执行eat - 存取器(getter & setter):用以改变属性的读取和赋值行为
- 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如
public表示公有属性或方法 - 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
- 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口
接口interface
接口interface是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
interface Test {
name: string;
age?: number;//?:可选属性
readonly id: number;//readonly只读属性,不可赋值
//注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
[index:number]:string //接口中可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。
}
联合类型和接口
interface RunOptions {
program:string;
commandline:string[]|string|(()=>string);
}
// commandline 是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"};
console.log(options.commandline)
// commandline 是字符串数组
options = {program:"test1",commandline:["Hello","World"]};
console.log(options.commandline[0]);
console.log(options.commandline[1]);
// commandline 是一个函数表达式
options = {program:"test1",commandline:()=>{return "**Hello World**";}};
var fn:any = options.commandline;
console.log(fn());
接口和数组
接口中可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集。
interface namelist {
[index:number]:string
}
var list2:namelist = ["John",1,"Bran"] // 错误元素 1 不是 string 类型
interface ages {
[index:string]:number
}
var agelist:ages;
agelist["John"] = 15 // 正确
agelist[2] = "nine" // 错误
接口继承
接口继承指接口可以通过其他接口来扩展自己。Typescript 允许接口继承多个接口。继承使用关键字 extends。
单接口继承语法格式:
Child_interface_name extends super_interface_name
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name
继承的各个接口使用逗号 , 分隔。
类class
属性和方法
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):
- 字段 − 字段是类里面声明的变量。字段表示对象的有关数据。
- 构造函数 − 类实例化时调用,可以为类的对象分配内存。
- 方法 − 方法为对象要执行的操作。
使用 class 定义类,使用 constructor 定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
//this 关键字表示当前类实例化的对象。构造函数的参数名与字段名相同。
this.engine = engine
}
// 方法
disp():void {
console.log("函数中显示发动机型号 : "+this.engine)
}
}
//使用 new 关键字来实例化类的对象,类实例化时会调用构造函数,类中的字段属性和方法可以使用 **.** 号来访问。
var obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+obj.engine)
// 访问方法
obj.disp()
访问控制修饰符(关键字)
TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
- public(默认) : 公有,可以在任何地方被访问。
- protected : 受保护,可以被其自身以及其子类和父类访问。当构造函数修饰为
protected时,该类只允许被继承。 - private : 私有,只能被其定义所在的类访问。使用
private修饰的属性或方法,在子类中也是不允许访问的。当构造函数修饰为private时,该类不允许被继承或者实例化。
readonly
- 只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。
- 如果
readonly和其他访问修饰符同时存在的话,需要写在其后面。
abstract
- 用于定义抽象类和其中的抽象方法。
- 抽象类是不允许被实例化的。
- 抽象类中的抽象方法必须被子类实现。
存取器
使用 getter 和 setter 可以改变属性的赋值和读取行为。
class Animal {
constructor(name) {
this.name = name;
}
get name() {
return 'Jack';
}
set name(value) {
console.log('setter: ' + value);
}
}
let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack
静态方法
使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用。
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp() // 调用静态方法
instanceof 运算符
instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
class Person{ }
var obj = new Person()
var isPerson = obj instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);
类的继承
类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
TypeScript 一次只能继承一个类,不支持继承多个类,但 TypeScript 支持多重继承(A 继承 B,B 继承 C)。
class child_class_name extends parent_class_name
interface与class的区别和使用
- interface:接口只声明成员方法,不做实现(抽象)。
- class:类声明并实现方法。
类实现接口
interface ContentInterface {
getContent(): String;
//每个实现该接口的类都必须实现getContent方法
}
class Article implements ContentInterface {
// 必须实现getContent方法
public function getContent(): String {
return 'I am an article.';
}
}
class Passage implements ContentInterface {
// 但实现方式可以不同
public function getContent(): String {
return 'I am a passage.'
}
}
class News implements ContentInterface {
// 没有实现getContent方法,编译器会报错
}
let a = new Article();
let p = new Passage();
print(a); // "I am an article."
print(p); // "I am a passage."
接口继承类
类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
extends和implements区别和使用
- 在类的声明中,通过关键字extends来创建一个类的子类。关键字implements声明类使用一个或者多个接口。
- extends 可为类继承某个类, 获取父类的所有的静态属性,继承之后可以使用父类的方法, 也可以重写父类的方法。
- extends 可做接口的接口(类)继承,通过其他接口(类)来扩展自己,可多接口继承。
- implements 可实现类的多个接口继承, 接口的方法一般为空的, 必须重写方法才能使用 。
class A(类) extends B(类) implements C,D,E(接口)//类
Child_interface(接口) extends super_interface1(接口), super_interface2(接口),…,super_interfaceN(接口)//接口