小白白typescript基础 (三) 继承 多态 接口

240 阅读7分钟

类的定义

 
        // ts中定义类:


            class Person{

                name:string;   //属性  前面省略了public关键词

                constructor(n:string){  //构造函数   实例化类的时候触发的方法
                    this.name=n;
                }

                run():void{

                    alert(this.name);
                }

            }
            var p=new Person('张三');

            p.run()   
  class Person{

        name:string; 

        constructor(name:string){  //构造函数   实例化类的时候触发的方法
            this.name=name;
        }

        getName():string{

            return this.name;
        }
        setName(name:string):void{

            this.name=name;
        }
    }
    var p=new Person('张三');

    alert(p.getName());


    p.setName('李四');


    alert(p.getName());

继承

ts中实现继承 extends、 super。子类中有父类共同方法的时候,子类调用自己的,就近原则。



   class Person{

        name:string;

        constructor(name:string){
            this.name=name;
        }

        run():string{

            return `${this.name}在运动`
        }
    }
    var p=new Person('王五');
    alert(p.run())


    class Web extends Person{
        constructor(name:string){

            super(name);  /*初始化父类的构造函数*/
        }
    }


    var w=new Web('李四');
    alert(w.run());


  

类里面的修饰符

typescript里面定义属性的时候给我们提供了 三种修饰符

public :公有          在当前类里面、 子类  、类外面都可以访问
protected:保护类型    在当前类里面、子类里面可以访问 ,在类外部没法访问
private :私有         在当前类里面可以访问,子类、类外部都没法访问

属性如果不加修饰符 默认就是 公有 (public

静态属性 静态方法

   es5  中  静态属性 静态方法  
    function Person(){
        this.run1=function(){

        }
    }
    Person.name='哈哈哈';

    Person.run2=function(){  静态方法


    }
    var p=new Person();

    Person.run2(); 静态方法的调用

ts   静态属性 静态方法   使用  static修饰。
     class Per{
        public name:string;
        public age:number=20;
        //静态属性

        static sex="男";
        constructor(name:string) {
                this.name=name;
        }
        run(){  /*实例方法*/

            alert(`${this.name}在运动`)
        }
        work(){

            alert(`${this.name}在工作`)
        }
        static print(){  /*静态方法  里面没法直接调用类里面的属性*/

            alert('print方法'+Per.sex);
        }
    }

    // var p=new Per('张三');

    // p.run();

    Per.print();

    alert(Per.sex);

多态(抽象类)

typescript中的抽象类:它是提供其他类继承的基类,不能直接被实例化。

用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。

abstract抽象方法只能放在抽象类里面

抽象类和抽象方法用来定义标准

【 多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现

多态属于继承】

一个抽象类 Animal


abstract class Animal{
    
    public name:string;
    constructor(name:string){

        this.name=name;

    }
    abstract eat():any;  //抽象方法不包含具体实现并且必须在派生类中实现。
    
    run(){

        console.log('其他方法可以不实现')
    }
}


// var a=new Animal() /*错误的写法*/
 


class Dog extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    eat(){

        console.log(this.name+'吃粮食')
    }
}

var d=new Dog('小花花');
d.eat();




class Cat extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    run(){


    }
    eat(){

        console.log(this.name+'吃老鼠')
    }
    
}

var c=new Cat('小花猫');
c.eat();


接口

接口的作用:在面向对象的编程中,接口是一种规范的定义, 它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。 接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据, 也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法 ,提供这些方法的类就可以满足实际需要。

typescrip中的接口类似于java, 同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

可参考这文章的描述:

juejin.cn/post/684490…

属性类接口

对传入的对象的【属性】 进行约束


        就是传入对象的约束    属性接口
         interface FullName{

            firstName:string;   //注意;结束   
            secondName:string;

        }

        function printName(name:FullName){

            // 必须传入对象  firstName  secondName
            console.log(name.firstName+'--'+name.secondName);
        }
        // printName('1213');  //错误

        var obj={   /*传入的参数必须包含 firstName  secondName  属性的顺序不约束 */   
            age:20,
            firstName:'张',
            secondName:'三'
        };
        printName(obj)

可选属性 约束

通过在属性后加 ?  实现可选性 


    interface FullName{
        firstName:string;
        secondName?:string;
    }

    function getName(name:FullName){

        console.log(name)
    }  
    getName({               
        firstName:'firstName'
    })


函数类型接口


 函数类型接口:对方法传入的参数 以及返回值进行约束    批量约束 
 举例::函数类型接口


函数接口定义:
interface encrypt{
    (key:string,value:string):string;
}

使用函数接口,规定了 函数的参数值类型和返回值类型
var md5:encrypt=function(key:string,value:string):string{
        //模拟操作
        return key+value;
}

console.log(md5('name','zhangsan'));



var sha1:encrypt=function(key:string,value:string):string{

    //模拟操作
    return key+'----'+value;
}

console.log(sha1('name','lisi'));
 

可索引接口

可索引接口 对数组的约束


                interface UserArr{
                    [index:number]:string
                    索引:number类型-----值类型:string类型
                }

                    引用  UserArr 接口
                // var arr:UserArr=['aaa','bbb'];

                // console.log(arr[0]);



                var arr:UserArr=[123,'bbb'];  /*错误*/

                console.log(arr[0]);


        可索引接口 对对象的约束



               定义对象约束的接口
                interface UserObj{

                    [index:string]:string
                    
                    对象的属性名:string类型 ----属性值:string类型
                }

                引用  UserObj 接口:
                var arr:UserObj={name:'张三'};

 

类类型接口

类类型接口:对类的约束(属性和方法 返回值的约束)  和   抽象类抽象有点相似    


interface Animal{
    name:string;
    eat(str:string):void;
}

class Dog1 implements Animal{

    name:string;
    constructor(name:string){

        this.name=name;

    }
    eat(){

        console.log(this.name+'吃粮食')
    }
}


var d=new Dog1('小黑');
d.eat();


class Cat1 implements Animal{
    name:string;
    constructor(name:string){

        this.name=name;

    }
    eat(food:string){

        console.log(this.name+'吃'+food);
    }
      }

var c=new Cat1('小花');
c.eat('老鼠');

接口扩展

 1: 接口扩展:接口可以继承接口   

    interface Animal{

        eat():void;
    }

    interface Person extends Animal{

        work():void;
    }

    class Web implements Person{

        public name:string;
        constructor(name:string){
            this.name=name;
        }

        eat(){

            console.log(this.name+'喜欢吃馒头')
        }
        work(){

            console.log(this.name+'写代码');
        }
        
    }

    var w=new Web('小李');

    w.eat();

2:类可以继承 和实现一起使用

   class 类名 extends 要继承的父类 implements 要实现的接口{
   
   }

typeScript中的泛型

泛型的定义

 泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。
 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 
这样用户就可以以自己的数据类型来使用组件。


通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

 举例: 想要实现这个功能:传入的参数和返回的参数一致的需求

只能返回string类型的数据

    function getData(value:string):string{
        return value;
    }

同时返回 string类型 和number类型  (代码冗余)


    function getData1(value:string):string{
        return value;
    }


    function getData2(value:number):number{
        return value;
    }




同时返回 string类型 和number类型       any可以解决这个问题


     function getData(value:any):any{
        return '哈哈哈';
    }


    getData(123);

    getData('str');


    

any放弃了类型检查,传入什么 返回什么。比如:传入number 类型必须返回number类型  传入 string类型必须返回string类型


    传入的参数类型和返回的参数类型可以不一致
       function getData(value:any):any{
            return '哈哈哈';
        }


泛型:可以支持不特定的数据类型   



T表示泛型,具体什么类型是调用这个方法的时候决定的

举例:想要实现这个功能:传入的参数和返回的参数一致的需求

       function getData<T>(value:T):T{
           return value;
       }
        getData<number>(123);

        getData<string>('1214231');


       getData<number>('2112');       /*错误的写法*/  




   举例: 想要实现这个功能:
   
   传入的参数指定,和返回的参数any的需求
       function getData<T>(value:T):any{
           return '2145214214';
       }

       getData<number>(123);  //参数必须是number

       getData<string>('这是一个泛型'); 


泛型类

举例: 要实现 写 最小值的算法 需要同时支持返回数字和 字符串 a-z 通过类的泛型来实现

  



 普通的写法

            class MinClass{
                public list:number[]=[];
                add(num:number){
                    this.list.push(num)
                }
                min():number{
                    var minNum=this.list[0];
                    for(var i=0;i<this.list.length;i++){
                        if(minNum>this.list[i]){
                            minNum=this.list[i];
                        }
                    }
                    return minNum;
                }

            }

            var m=new MinClass();

            m.add(3);
            m.add(22);
            m.add(23);
            m.add(6);

            m.add(7);
            alert(m.min());



上面的普通类需要写两个类

使用类的泛型实现


class MinClas<T>{

    public list:T[]=[];

    add(value:T):void{

        this.list.push(value);
    }

    min():T{        
        var minNum=this.list[0];
        for(var i=0;i<this.list.length;i++){
            if(minNum>this.list[i]){
                minNum=this.list[i];
            }
        }
        return minNum;
    }
}

var m1=new MinClas<number>();   /*实例化类 并且制定了类的T代表的类型是number*/
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min())


var m2=new MinClas<string>();   /*实例化类 并且制定了类的T代表的类型是string*/

m2.add('c');
m2.add('a');
m2.add('v');
alert(m2.min())



把类作为参数的泛型类

1、定义个类

2、把类作为参数来约束数据传入的类型

把类作为参数来约束数据传入的类型 

class User{
    username:string | undefined;
    pasword:string | undefined;
}


class MysqlDb{
    add(user:User):boolean{

        console.log(user);
        return true;
    }

}
var u=new User();
u.username='张三';
u.pasword='123456';
var Db=new MysqlDb();
Db.add(u);

泛型接口

  
        interface ConfigFn<T>{
            (value:T):T;
        }


        function getData<T>(value:T):T{

            return value;
        }

        
        var myGetData:ConfigFn<string>=getData;     


        myGetData('20');  /*正确*/


        // myGetData(20)  //错误

      
        function  getName<T>(key:T):number{
            return  12

          }