最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • TypeScript 面向对象编程(类 接口与泛型)

    正文概述 掘金(花猫儿)   2021-01-18   407

    面向对象

    TypeScript 是面向对象类的编程。

    什么是面向对象呢?

    简而言之,就是程序中所有的操作,都是通过对象来完成的。计算机程序本质是对现实事物的抽象。一个人,一辆车,一只狗,这些都是对象,而这些对象发出的动作就是对象的方法,某些特征就是对象的属性。比如一个人,他的身高,长相,姓名,年龄等这些在对象中都是他的属性,而他发出的动作,走,跑,说话等这些在对象中都是他的方法。

    类是什么?

    类其实就是对象的模型,通过类可以来创建对象。对象的属性和方法,要在类中明示的表示出来。

    下面定义一个简单的类:

    class Person {
      name: string = 'xiaobai';
      static age: number = 18;
      say() {
        console.log('hello');
      }
      static run() {
        console.log('run');
      }
    }
    let person = new Person()
    

    上面定义了一个简单的类,通过 new 关键字,实例化成对象。name 是实例对象。

    static 指的是类的静态属性,用类名访问,无需创建对象,比如 Person.age。但是实例对象访问不到。静态方法与静态属性使用方式相同。

    类的构造函数 constructor

    为什么需要它呢?

    当我们在创建类的时候,通常都不可能只实例化一个对象,通常会实例化多个对象。

    // 这样创建出来的实例对象都是相同的属性值和方法
    class Person {
      name: string = 'xiaobai';
      say() {
        console.log('hello');
      }
    }
    let person = new Person()
    

    constructor 这个构造函数在每次 new 实例化对象,立即执行。

    class Person {
      name: string;
      constructor(name: string) {
        this.name = name;
        console.log(this);  // 它指向的是per这个实例化的对象
      }
    }
    let per1 = new Person('xiaobai1');
    let per2 = new Person('xiaobai2');
    let per3 = new Person('xiaobai3');
    

    在每次实例化对象完成之后,在 constructor 函数里面会生成一个 this 这个 this 指向的就是实例化产生的对象。

    通过this.name 添加属性,就相当于往实例化的对象里面添加属性。这样我们再把实例化时传的参数带进去,这样就会创建出不同属性值的对象了。方法的话,就是哪个实例对象调用方法,方法里面的this就指向谁。

    类的继承 extends

    class Dog {
      name: string;
      age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
      say() {
        console.log('汪汪');
      }
    }
    
    class Cat {
      name: string;
      age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
      say() {
        console.log('喵喵');
      }
    }
    

    我们分别创建一个 Dog 和 Cat 类,我们发现它们都有相同的属性和方法,这样的代码我们重复写了两遍,如果我们再去创建一个牛,蛇,猪等更多的类,这样就开始做重复的工作了。

    因此我们使用继承来简化它:

    class Animal {
      name: string;
      age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
      say() {
        console.log('叫');
      }
    }
    class Dog extends Animal {
      run() {
        console.log(`${this.name}在跑`);
      }
      // 重写父类方法
      say() {
        console.log('汪汪')
      }
    }
    
    class Cat extends Animal {
      // 重写父类方法
      say() {
        console.log('喵喵')
      }
    }
    let dog = new Dog('小白', 3);
    console.log(dog);      // {name: "小白", age: 3}
    dog.say();  // 汪汪
    let cat = new Cat('小黑', 2);
    console.log(cat);      // {name: "小黑", age: 2}
    dog.say();  // 喵喵
    

    从上面代码可以看出,我们使用了 extends 关键字来继承 Animal 这个类,从而使 DogCat 这两个类,都拥有了 Animal 类上的方法。这大大简化了我们的代码量,而且不用在去做重复的工作。

    继承的子类,不仅有拥有父类的方法,还能有自己的方法,比如,子类 Dog 中的 run 方法。

    如果继承的子类中添加了与父类相同的方法,子类的方法将覆盖父类的方法。这个子类方法覆盖掉父类的方法的形式,称为方法的重写

    super 关键字

    先写一段代码:

    class Animal {
      name: string;
      constructor(name: string) {
        this.name = name;
      }
      say() {
        console.log('叫');
      }
    }
    class Dog extends Animal {
      age: number;
      constructor(name: string, age: number) {
        super(name);   // 调用父类的构造函数
        this.age = age;
      }
      say() {
        super.say()    // 调用父类的方法
      }
    }
    let dog = new Dog('小白', 3);
    console.log(dog);
    

    在子类的方法中使用 super 表示当前类的父类。

    在子类的添加新的属性,如果在子类中写了新的构造函数,子类构造函数必须对父类构造函数进行调用。

    抽象类

    有的时候,我们并不需要父类来实例化创建对象,父类是一个超类,只用来存放公用的属性和方法,用来继承使用。这个时候就用到了抽象类,抽象类只能用来继承,而不能用来实例化创建对象。

    abstract class Animal {
      name: string;
      constructor(name: string) {
        this.name = name;
      }
      abstract say(): void;
    }
    class Dog extends Animal {
      say() {
        console.log('叫');
      }
    }
    

    在 abstract 抽象类中,才能定义抽象方法,子类必须对抽象方法进行重写。抽象方法使用 abstract 开头,没有方法体。抽象类中,可以不写抽象方法。

    类的修饰符

    类的修饰符 有三个 public private protected

    public

    公共属性,修饰的属性可以在任意位置进行访问(修改),包括继承的子类

    属性前不设置修饰符时 默认为 public

    class Person {
      public name: string;
      public age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    }
    let person = new Person('孙悟空', 18);
    console.log(person);    // 输出 {name: "孙悟空", age: 18}
    person.name = '猪八戒';
    person.age = 20;
    console.log(person);    // 此时输出 {name: "猪八戒", age: 20}
    

    此时可以看出使用 public 修饰属性:

    属性可以在实例化对象中任意被修改,这样使对象中的数据变得非常不安全。

    private

    私有属性,只能在类内部进行访问(修改)

    此时我们将 Person 类中的,name属性改成 私有属性,结果如下:

    class Person {
      private name: string;
      public age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    }
    let person = new Person('孙悟空', 18);
    console.log(person);    // 输出 {name: "孙悟空", age: 18}
    person.name = '猪八戒';  // 此时抛出错误,“属性‘name’为私有属性,只能在 Person 类中访问”
    

    这样属性被私有化,外部就不能 以对象点属性的方法去访问了,那么我们可以通过 向类中添加方法去访问(修改)里面的属性,如下:

    class Person {
      private name: string;
      public age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    
      getName () {
        return this.name;
      }
    
      setName (value: string) {
        this.name = value;
      }
    }
    let person = new Person('孙悟空', 18);
    person.setName('猪八戒');
    console.log(person.getName());   // 打印出 '猪八戒'
    

    可以通过设置 setName 方法,在对象内部改变去修改 name 这个私有属性。

    当然也可以直接直接使用 TS 提供的 getter , setter 方法,代码如下:

    class Person {
      private name: string;
      public age: number;
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    
      get _name() {
        return this.name;
      }
    
      set _name(value: string) {
        this.name = value;
      }
    }
    let person = new Person('孙悟空', 18);
    person._name = '猪八戒';
    console.log(person._name);   // '猪八戒'
    

    private可以做属性的封装,不直接去访问它的属性,通过 getter,setter 方法去访问。

    protected

    受保护的属性,只能在当前类和子类中使用(修改),不能在实例化的对象中去访问。

    接口

    接口实现对象

    接口用来定义一个类结构,用来定义一个类中应该哪些属性和方法,同时接口也可以当做类型声明去使用。

    举个例子:

    interface User {
      name: string;
      age: number;
    }
    
    interface User {
      gender: string;
    }
    
    const USER1: User = {
      name: '小明',
      age: 18,
      gender: '男'
    }
    
    console.log(USER1);
    

    我们定义一个 user 对象的接口,声明的第一个接口中包括,name 和 number 属性,声明第二个接口包含 gender 属性,我们可以看到两个接口可以重复声明,并且两个接口中的属性检测会合并,我们再去使用这个接口时,就必须有 name age gender。

    接口实现类

    接口可以在定义类的时候去限制类的解构

    接口定义类的特点:

    • 接口中所有的属性都不能有实际值
    • 接口只定义对象结构,而不考虑实际值
    • 在接口中所有的方法都是抽象方法

    定义类时,可以使类去实现一个接口,实现接口就是使类满足接口的要求

    /**
     * 接口实现类
     */
    interface user {
      name: string;
      say(): void;
    }
    
    class user1 implements user {
      name: string;
      constructor(name: string) {
        this.name = name;
      }
      say() {
        console.log('hello');
      }
    }
    

    由此可以看出,接口很像抽象类,但是也有很显著的区别:

    • 在接口中的方法都是抽象方法,不能有实际的值,在抽象方法中可以有抽象方法,也可以有普通方法
    • 在使用接口的时候,使用关键字 implements 实现,在使用抽象类的时候,使用 extends 继承

    本质上两者都是对类定义一个标准,使实现接口,或者继承抽象方法的类,必须去符合这个标准。

    泛型

    在定义函数或者类时,如果遇到类型不明确的就可以使用泛型。

    当我们不明确函数传参是什么类型的时候,往往会使用 any 来表示任意类型,但是使用 any ,会关闭 TS 的类型检测,因此这里要用泛型来代替。

    举个简单的代码案例:

    // 使用any,关闭类型检测
    function fn(a: any): any {
       return a;
    }
    
    // 使用泛型,自动判断类型
    function fn<T> (a: T): T {
      return a;
    }
    fn<string>('hello');  // 也可以在调用的时候,自己指定类型
    

    类使用泛型:

    class User<T> {
      name: T;
      constructor(name: T) {
        this.name = name;
      }
    }
    let user = new User<string>('zhangsan');
    

    起源地下载网 » TypeScript 面向对象编程(类 接口与泛型)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元