[TS基础]对象,类,属性

一.类(class)

  • 类可以理解为对象的模型,通过类来创建对象

1.属性与方法

  • 一个类主要包含两个部分,属性与方法
// 使用class关键字定义一个类
/**
 * 类主要包含两部分:
 * 1.属性
 * 2.方法
 */
class Person {
    // 静态属性,从属于类  可以直接通过类来访问
    static id: number = 9527;
    // 示例属性,从属于对象  需要通过类的实例对象去访问
    name: string = "iFinder";
    age: number = 24;
    // 只读属性, readonly开头,不能更改只能读取
    readonly country:string = "china";

    // 方法
    // 同理如果方法用static修饰,该方法便可以通过类去调用
    sayGood() {
        console.log("Good !");
    }
}

const per = new Person();
per.sayGood();
console.log(per.name);
console.log(per.age);
// 静态属性
console.log(Person.id);

2.构造器

  • 创建多个对象的时候,我们希望在创建对象时就赋予它不同的属性,这时就可以通过构造器来实现这样的需求
class Dog {
    name: string
    age: number
    /**
     * 构造器,在创建多个对象的时候,创建对象时调用的函数
     */
    constructor(name: string, age: number) {
        // this表示的就是当前的示例,可以通过他向新建的对象中添加属性
        this.name = name
        this.age = age
    }
    bark() {
        alert('汪 !')
    }
}

class Cat {
    // ts也可以将属性快速的定义在构造器当中, 简化了属性的写法
    constructor(public name:string, public age:number) {

    }
}

const dog1 = new Dog('dog1', 4)
const dog2 = new Dog('dog2', 5)
const dog3 = new Dog('dog3', 6)
console.log(dog1)
console.log(dog2)
console.log(dog3)

3.继承

  • 可以通过继承,将多个类共有的属性与方法抽象出来,作为公共的父类.这样可以大大提高代码的利用率
  • 子类直接继承父类,可以直接拥有父类的属性与方法
(function(){
    // 创建一个表示动物的类
    // 通过继承,可以把多个类共有得属性与方法抽象成公共得父类,这样就提高了代码得复用性
    class Animal {
        name: string 
        age: number
        constructor(name: string, age: number){
            this.name = name
            this.age = age
        }
        sayHello() {
            console.log(`${this.name} 在 叫 !`)
        }
    }

    // 让Dog类继承自动物类
    // 这时Animal就是Dog的父类,子类将会拥有父类所有的方法与属性
    class Dog extends Animal {
        // 可以实现自己独有得方法
        run() {
            console.log(`${this.name} 在 跑!`)
        }
        // 可以重写父类的方法实现自己特有的功能
        // 子类的方法会覆盖父类的方法
        sayHello() {
            console.log(`${this.name} 在 汪汪汪 !`)
        }
    }
    class Cat extends Animal {
        sayHello() {
            console.log(`${this.name} 在 喵喵喵 !`)
        }
    }
    const dog = new Dog('小黑狗', 4)
    const cat = new Cat('小花猫', 6)
    dog.sayHello()
    cat.sayHello()
})()

4.super关键字

  • 子类继承父类之后,如果想调用父类中的属性或者方法,可以通过super关键字
  • 子类如果重新实现了构造器,那么需要在自己的构造器中通过super调用父类的构造器
(()=>{
    class Animal {
        name: string
        constructor(name:string) {
            this.name = name
        }
        sayHello() {
            console.log("动物叫")
        }
    }

    class Dog extends Animal {
        age: number
        // 如果在子类中重新实现了构造器,那么需要通过super调用父类的构造器
        constructor(name:string, age:number) {
            super(name)
            // 子类新添加的属性需要自己实现
            this.age = age
        }
        sayHello() {
            // 在类的方法中,super表示当前类的父类
            // 这里可以理解为直接调用了父类的sayHello方法
            super.sayHello()
        }
    }

    const dog = new Dog('小黑', 8)
    dog.sayHello()
})()

二.抽象类与抽象方法

  • 当你定义了一个公共父类,并且只想被继承,不想拥有具体实例的时候就可以通过abstract修饰,使之成为抽象类
  • 抽象类中你想定义子类必须实现的某些方法,可以定义抽象方法
(()=>{
    /**
     * 以abstract开头的类是抽象类
     * 只能被继承,不能直接实例化
     * 
     * 抽象类中可以添加抽象方法(规定一个必须实现的方法,让不同的类去实现)
     */
    abstract class Animal {
        name: string
        constructor(name:string) {
            this.name = name
        }

        // 不定义具体的实现,由子类去实现具体的方法体
        // 抽象方法只能被定义在抽象类中
        abstract sayHello(): void
    }

    class Dog extends Animal {
        // 抽象方法会强制子类去添加具体的实现
        sayHello(): void {
            console.log(`${this.name} 在 汪汪汪 !`)
        }
    }
    const dog = new Dog('小黑')
    dog.sayHello()
})()

三.接口

(()=>{
    // type关键字描述对象的类型
    type myType = {
        name: string,
        age: number
    }

    /**
     * 接口用来定义一个类的结构
     * 可以定义一个类型中应该包含哪些方法
     */
    interface myInterFace {
        name: string
        age: number
    }

    // 接口可以重复声明,但是在作为类型使用的时候属性是叠加的
    interface myInterFace {
        gender: string
    }

    /**
    * 接口可以在定义类的时候限制类的结构
    * 接口中的所有属性都不能有实际的值
    * 接口值定义对象的结构,不考虑实际的值
    */
    interface inter{
        name: string
        sayHello(): void
    }

    // 定义类的时候可以让这个类实现这个接口
    class MyClass implements inter {
        name: string = "iFinder"
        sayHello(): void {
            //...
        }
    }
})()

四.属性的封装

  • TS的类中的属性,如果不加以修饰的话就是任何人都能访问与修改的,这样就造成的属性数据的不安全
  • 通过封装,可以将属性一定程度上的保护起来
  • 封装后只提供给调用方相应的方法,这样设置与获取数据的方法就是开发者可控的,提高了数据的安全性
(()=>{
    // 定义一个人类
    class Person {
        /**
         * 有的时候我们不希望对象中的属性被随意的修改,这时就需要将属性封装起来
         * 这时候可以通过属性修饰符来对属性进行封装
         * 
         * public: (默认)修饰的属性可以再任意位置被访问
         * private: 私有属性,只能在类的内部进行访问与修改
         *   --这时通过在类中添加方法,让外部通过这个方法访问这个属性
         *   --这时修改与访问的方法都是开发者提供的,这样这个属性的访问就变得可控了
         * protected: 当前类和子类能都访问与修改,外部不能访问与修改
         */
        private _name:string
        private _age:number

        constructor(name:string, age:number) {
            this._name = name
            this._age = age
        }

        // 给外部的类提供一个访问私有属性的方法
        getName():string {
            return this._name;
        }
        // set的时候限制name的类型
        setName(name:string) {
            this._name = name;
        }
        // set的时候限制年龄不会为负值
        setAge(age:number) {
            if(age >= 1) {
                this._age = age;
            }
        }

        // TS中独有的getter和setter方法
        get age():number {
            return this._age >= 1 ? this._age : 1;
        }
        set age(age:number) {
            if(age >= 1) {
                this._age = age;
            }
        }
    }

    // TS独有的写法可以直接用类似属性的方法来进行设置
    const p = new Person("iFinder", 25);
    console.log(p.age);  // 这时会调用get age方法获取属性
    p.age = -1;  // 这时会调用set age方法设置属性
    console.log(p.age);  // 方法中有判断,此时的打印依旧是25
})()

五.泛型

  • 定义函数或者声明一个类的时候如果暂时不能确定具体的类型,但是又想保持某种类型的统一,不想通过any破环TS的类型检查机制,就可以通过指定泛型的方式来达到这个要求
(()=>{
    /**
     * 定义函数或者类的时候,如果遇到类型不明确的,可以使用泛型
     *   <V>定义了一个叫V的泛型
     */
    function fn<V>(a: V): V {
        return a;
    }

    // 直接调用具有泛型的函数,这时泛型的类型就是number
    let a:number = fn(10)
    // 可以直接指定泛型的类型
    let s:string = fn<string>('iFinder')

    //可以指定多个泛型
    function fn1<K, T>(a: T, b: K): T {
        return a;
    }

    // 定义的时候就指定泛型的类型
    interface Inter{
        length:number
        getLength(): number
    }
    abstract class Animal {
        info:string;
        constructor(private _name:string, private _age:number) {
            this.info = `name: ${_name}, age: ${_age}`
        }
        get name(){
            return this._name
        }
        set age(age:number) {
            this._age = age
        }
    }

    function fn2<T extends Inter, K extends Animal>(a: T, b: K): K {
        return b
    }

    // 通过泛型指定类中的某种类型
    class MyClass<T>{
        constructor(public name:T) {}
    }
    // 创建类的时候确定泛型类型
    let my = new MyClass<string>("iFinder")
})()

笔记说明

笔记markdown文件+项目源码
B站对应视频

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值