目录
接口和多态
接口是一种自定义类型, 也就是类型了, 所以不但可以声明变量的类型,也可以声明函数参数(也是变量类型),函数返回值的类型
一、接口定义函数变量类型
//函数类型接口
interface addType {
(bValue: number, secValue: number):number
}
function add(x: number, y: number): number {
return x + y;
}
let myadd1:addType = add;
let myadd2:addType = (x:number, y:number):number=>{
return x+y;
}
二、接口与对象
(1)对象是字面量对象, 对象中成员必须与接口中声明的成员完全相同,不可多,也不可少
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string ,
[prop:string]:any;//你可以随便扩展 值是任意类型 的 任意属性
}
let teacher:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
console.log(teacher);
以下代码也是对的
let teacher: {
firstName:string,
lastName:string,
sayHi: ()=>string
} = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
(2)对象是通过new 出的对象, 对象中成员必须包含接口中声明的成员不可少,但是**可以增加接口中未声明的成员**
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
class Teacher {
firstName:string="小五";
lastName:string="小二";
age:number= 30; //接口中没有声明,但是不会错
sayHi():string {
return "Hi there";
}
}
let teacher:IPerson = new Teacher();
console.log(teacher);
以下代码也是对的
let teacher:{
firstName:string,
lastName:string,
sayHi: ()=>string
} = new Teacher();
(3)类型断言情况下。对象中成员只能是接口中声明过的成员,但是可少
对于下面示例中stu对象中的成员可以包含firstName,lastName,sayHI, 可以少,不能出现接口中没有出现过的
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
let stu:IPerson = <IPerson> {};
stu.firstName = "司空";
stu.sayHi = ():string =>{return "Hi there"}
console.log(stu);
//stu.xx = "dfds"//错,因为接口中没有出现过
三、接口与数组
接口可以规定数组中元素的索引类型和元素类型,先看一个与默认情况相同的示例
//规定以number为元素索引、string为元素类型
interface Inamelist {
[index:number]: string
}
let list: string[] = ["John","Bran"]
list[2] = "jeep";
console.log(list);
console.log(list[0]);
console.log(list[1]);
console.log(list[2]);
也可以使用非number类型为元素索引
//规定以string为元素索引、string为元素类型
interface Inamelist {
[index: string]: string
}
let list: Inamelist = [] as unknown as Inamelist;
list['a'] = "好的";
list['b'] = "不错的";
console.log(list);
console.log(list['a']);//好的
console.log(list["b"]);//不错的
四、接口继承接口
接口继承接口后,子接口就除了自身接口声明之外还包含了父接口声明
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
接口继承接口是可以多继承的
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
//Iparent1和Iparent2顺序是无关仅要的
interface Child extends IParent1, IParent2 {
v3:string
}
五、类实现接口
> 类可以实现接口,并可以多实现
> 类实现接口后,类体中必须实现接口所有字段和方法,当然类可以扩展自己本质的成员
interface IShape {
draw():void;
size:number;
}
interface IName {
name: string;
}
class Circle implements IShape, IName {
public size:number = 30;
public name:string = "圆";
public draw():void {
console.log("会绘制一个"+this.name);
}
public show() {
console.log("本来是Circle");
}
}
let c:Circle = new Circle();
c.draw();
c.size = 31;
c.name = "四边型";
c.show();
类可以继承父类的同时实现接口
interface IShape {
draw():void;
size:number;
}
interface IName {
name: string;
}
class Shape {
public showArea():void {
console.log("面积是?平方")
}
}
class Circle extends Shape implements IShape, IName {
public size:number = 30;
public name:string = "圆";
public draw():void {
console.log("会绘制一个"+this.name);
}
public show() {
console.log("本来是Circle");
}
}
let c:Circle = new Circle();
c.draw();
c.size = 31;
c.name = "四边型";
c.showArea();
c.show();
六、 泛型函数类型接口(见泛型章节 )
//泛型函数类型接口1
interface GenericIdentityFn1 {
(arg: T): T;
}
//泛型类函数型接口2
interface GenericIdentityFn2<T> {
(arg: T): T;
}
七、接口与泛型
八、接口变量指向实现类对象
接口变量可以引用接口实现类对象, 但是只能访问接口中声明过的成员, 接口变量也可赋值为null或undefined,
如果想使用此接口变量访问所有对象成员,那么可以对接口变量进行"类型断言"为对象所属类的类型。
interface IShape {
draw():void;
size:number;
}
interface IName {
name: string;
}
class Circle implements IShape, IName {
size:number = 30;
name:string = "圆";
draw():void {
console.log("会绘制一个"+this.name);
}
show() {
console.log("本来是Circle");
}
}
let c:IShape = new Circle();
c.draw();//对,因为IShape中出现过
c.size = 31;//对,因为IShape中出现过
//c.name = "四边型";//错
//c.show();//错
let c2 = <Circle>c;//类型断言
c2.name = "四边型";//对
c2.show();//对
九、多态
1 概念
多态概念: 一种状态多种表现形式
方法中this在编译时并不知道是哪个对象,执行过程中动态确定, 因为是在执行过程中确定的this,所以this属于运行时多态。
"接口变量指向实现类对象"或"父类指向子类对象+重写",可以实现运行时多态。
有了接口变量引用对象,或父类变量引用子类对象,可以非常清晰的代码实现动态代理设计模式。
2 接口变量实现多态
多态:程序设定的标准,可以实现出多种满足这个标准的方案
下面示例, 在myshow方法中的 "a.show()"在编译的时候并不确定是执行X中的show()还是执行Y中的show(),还是其它类中的show, 只有运行过程中才能确定,完美实现动态多态性
interface A {
show():void;
}
class X implements A {
show() {
console.log("这是X的show()")
}
}
class Y implements A {
show() {
console.log("这是Y的show()")
}
}
class Test {
myshow(a: A) { //a=new X() a=new Y()
a.show();
}
}
let x = new X();
let y = new Y();
let t = new Test();
t.myshow(x);//这是X的show()
t.myshow(y);//这是Y的show()
3 父类变量+重写实现多态
下面示例中, 同样 myshow方法中的 "a.show()" 在运行过程中才知道是调用哪个类中的show()
class A {
show() {
console.log("A中的show")
}
}
class X extends A {
show() {
super.show()
console.log("这是X的show()")
}
}
class Y extends A {
show() {
super.show();
console.log("这是Y的show()")
}
}
class Test {
myshow(a: A) {//a=new A() a=new X(); a=new Y();
a.show();
}
}
let y = new Y();
let t = new Test();
t.myshow(new X());//这是X的show()
t.myshow(new Y());//这是Y的show()
t.myshow(new A());//主是A的show()