美文网首页
bunny笔记|TS基础(3):给类定义属性、构造函数、Gett

bunny笔记|TS基础(3):给类定义属性、构造函数、Gett

作者: 一只小小小bunny | 来源:发表于2022-05-03 11:59 被阅读0次

    01

    给类定义属性

    class Point {
        // x: number = 2
        // y: number = 4
    
        x: number
        y: number
        constructor() {
            this.x = 2222
            this.y = 22255
        }
    }
    
    const pt = new Point()
    pt.x = 33
    pt.y = 22
    
    //也可以断言
    
    class OKG{
        name!:string
    }
    

    02

    class Greater {
        readonly name: string = 'world'
        constructor() {
            this.name = 'hello'
        }
    }
    
    const G = new Greater()
    //G.name = 'g' //报错,无法分配到name,因为他是只读属性
    
    //constructor() 是再new的时候运行的,可以传入参数,定义参数类型等
    
    class Greater2 {
        readonly name: string = 'world'
        constructor(other?: string) {
            if (other !== undefined) {
                this.name = other
            }
    
        }
    }
    
    const g = new Greater2('hello')
    console.log(g.name);
    
    
    

    03

    构造函数-constructor。可以定义参数,传初始值,然后再重新赋值即可

    class P {
        x: string;
        z: number
        constructor(x: string='', z: number=0) {
            this.x = x;
            this.z = z
        }
    }
    const t = new P()
    console.log(t.z);
    console.log(t.x);
    
    
    //注意:构造函数不能有类型参数,构造函数不能有返回类型注释
    
    

    04

    类里面的函数,我们称之为方法

    
    class Int {
        x: number;
        z: number
        constructor(x: number = 2, z: number = 0) {
            this.x = x;
            this.z = z
        }
    
        add(sum: number) {
            let y = this.z + this.x
            let su = sum + y
            console.log(y);
            console.log(su);
        }
    }
    
    const pg = new Int()
    pg.x = 4
    pg.z = 5
    pg.add(3)//传实参
    
    

    05

    Getters/Setters
    如果存在get,但没有set属性,则改属性自动是可读的
    如果没有指定setter参数的类型,它将从getter返回类型中推断出来
    //访问器和设置器必须有相同的成员可见性 get和set的函数方法名相同

    class C {
        _length = 9;
    
        get length() {
            return this._length;
        }
    
        set length(value) {
            this._length = value
        }
    }
    
    const cl = new C()
    console.log(cl.length);// 9
    
    

    06

    class MyClass {
        [s: string]: boolean | ((s: string) => boolean)
        x = true
    
        check(s: string) {
            return this[s] as boolean //断言
        }
    }
    
    

    07

    
    interface Pingable {
        ping(): void;
    }
    
    class SO implements Pingable {
        ping(): void {
            console.log("ping!");
    
        }
    }
    
    let so: SO = new SO()
    so.ping()
    
    interface A{
        x:number;
        y?:number
    }
    
    class C2 implements A{
        x=99
    }
    
    const cll=new C2()
    console.log(cll.x);//99
    //console.log(cll.y);//undefined,C2上不存在属性y
    
    

    08

    class Animal {
        dog: string
        constructor(dog: string = '') {
            this.dog = dog
        }
    }
    
    class Dog extends Animal {
        pick: string
        constructor(pick: string = '') {
            super()
            this.pick = pick
        }
    }
    
    const zoo = new Dog()
    console.log(zoo.dog = 'yellow');
    console.log(zoo.pick = 'pink');
    

    09

    重写方法(基类和派生类)

    //基类
    class Base {
        greet() {
            console.log('hello lady');
    
        }
    }
    
    //派生类
    class Derived extends Base {
        greet(name?: string): void {
            if (name === undefined) {
                super.greet()
            } else {
                console.log(name.toUpperCase());//toUpperCase()将传入的string转换为大写
            }
        }
    }
    
    const d = new Derived()
    d.greet()
    d.greet('reader')
    
    //注意:派生类要遵循基类的契约,契约就是,如Derived类覆盖Base类,一定要与Base兼容,比如这里传入的参数,如果name为必传参数那么就会报错,类型不匹配
    
    const b:Base =d
    b.greet()
    
    

    10

    基类和派生类初始化的顺序
    1.基类的字段被初始化
    2.基类构造函数运行
    3.派生类的字段被初始化
    4.派生类构造函数运行

    class Basic {
        name = "base";
        constructor() {
            console.log("my name is" + " " + this.name);
    
    
        }
    }
    
    class Deri extends Basic {
        name = "derived";
    }
    
    const dd = new Deri();
    
    //优先初始化 基类的初始值
    
    
    

    11

    继承内置类型,什么是内置类型呢?比如array,error,map等等,这些TS内置的一些对象.

    //例:
    
    class MsgError extends Error{
    
        constructor(m:string){
            super(m)
    
            // //es5及以下,可以明确地设置原型
            // Object.setPrototypeOf(this,MsgError.prototype)
    
        } 
        sayHello(){
            return 'hello ' + this.message
        }
    }
    
    const msgError=new MsgError('lady')
    console.log(msgError.sayHello()); //hello  lady
    
    
    //这里的定义了一个类叫MsgError,它继承了Error这个内置的对象,Error就是内置的一个类或者一个对象,有时候我们在分析内置类型的结构的时候,可能出乎我们的意料,这个呢,主要表现在我们编译的时候使用的是什么target,比如我们使用ES6以上的版本,我们可能不用关心太多的关于继承内置类型的一些问题,如果是ES5及以下的版本的话,就需要注意了
    

    12

    class A{
        constructor(){
    
        }
    
        public add(){
    
        }
    
        protected pro(){
    
        }
    
        private pri(){
    
        }
    }
    
    const a:A=new A()
    a.add()
    

    13

    类里的static区块

    static 静态成员和static # 静态的区别,最大的区别是:带#号的就变成了私有的这样的属性,比如说我们可以在类的内部通过getter来去访问,但访问的时候呢,我们仍旧是可以通过类名去访问它,同时我们在类里还可以写一个static这样的块,这个static后面可以直接跟这个大括号{},然后我们可以通过类名访问我们当前类里边的通过#号来定义的这些静态的属性,那我们在类的外边试图去访问一下这个#count 是行不通的,也就是说它是私有的

    
    
    class Foo {
        static #count = 0;
    
        get count() {
            return Foo.#count;
        }
    
        static {
            try {
                const lastInstances = {
                    length: 100
                }
                Foo.#count += lastInstances.length;
            }
            catch{
                //....
            }
        }
    }
    
    // Foo.#count //报错,属性#count在类FOO外部不可访问,因为它具有专用标识符
    
    

    14

    泛型类

    class Box<Type>{
        contents:Type
        constructor(value:Type){
            this.contents=value
        }
       // static defaultValue:Type//报错:静态成员不能引用类类型参数
    }
    
    const box:Box<string>=new Box('bunny')
    

    15

    类运行时的this

    class Myclass {
        name = "Myclass";
        // getName() {
        //     return this.name
        // }
    
        // //(1)箭头函数
        // getName=()=> {
        //     return this.name
        // }
    
        //(2)this参数
            getName(this:Myclass) {
            return this.name
        }
    }
    
    const c = new Myclass()
    console.log(c.getName());//Myclass
    const obj = {
        name: "obj",
        getName: c.getName
    }
    
    // console.log(obj.getName()); //obj
    
    //得到的name是const下的name,而不是我们初始化指向this下的name。解决方法:(1)箭头函数。(2)this参数
    
    //(1)使用箭头函数后得到的是Myclass
    //console.log(obj.getName()); //Myclass
    //(2)使用this参数后得到的是obj .就是说,谁调的我我就打印谁
    console.log(obj.getName()); //obj
    

    总结:
    为了保证我们类里边的某个函数的this指向,没有问题,我们可以采用箭头函数和this参数两种方法,使用的时候一定要权衡,this这个值保证在运行的时候是正确的,即使我们没有经过TS检查代码也是如此。第二呢,使用箭头函数,它会使用更多的内存,因为每个类实例将有它自己的副本每个函数都是这样定义的,第三个呢,使用箭头函数不能在派生类中使用super.getName,也就是我们不能在子类里边通过super来调父类这个方法了,因为在原型链中没有入口可以获得基类的方法,那如果是我们使用this参数这种方式来解决这个问题,它也有一些取舍的地方,首先呢,javascripe调用者仍然可能在不知不觉的错误中来用类的方法,比方说刚才我们最后的这个调用,另外呢,每个类只有一个函数被分配,而不是每个实例会创建一个函数,另外呢,基类方法这个定义仍然可以通过super来调用,这个要优于刚才我们说的箭头函数,所以采用哪种方法取决于我们正常的业务需求即可

    16

    class Boxes {
        contents: string = "";
        set(value: string) {
            this.contents = value
           // console.log(this);//Boxes { contents: 'hello' }
            return this;
        }
    }
    
    class ClearableBoxes extends Boxes {
        clear() {
            this.contents = ''
        }
    }
    const boxes = new Boxes()
    const bo = boxes.set('bunny')
    console.log(bo);//此时this返回的是 Boxes { contents: 'bunny' }
    // boxes.set('hello')
    
    const boxes1 = new ClearableBoxes()
    const bo1 = boxes1.set('bunny')
    console.log(bo1);//此时this返回的是 ClearableBoxes { contents: 'bunny' }
    
    

    17

    //基于类型守卫的this
    //this is Type
    
    class ValueBox<T>{
        value?: T
    
        hasValue(): this is { value: T } {
            return this.value !== undefined
        }
    }
    
    const valueBox = new ValueBox()
    valueBox.value = 'bunny'
    
    if (valueBox.hasValue()) {
        console.log(valueBox.value);//bunny 
    }
    
    

    18

    class Params {
        constructor(public readonly x: number = 9, y: number = 99, private a: string = 'bunny') {
            //...
        }
    }
    
    const p = new Params()
    
    //类表达式
    
    const someClass = class <Type>{
        content: Type
        constructor(value: Type) {
            this.content = value
        }
    }
    const m = new someClass('bunny')
    console.log(m.content)
    

    19

    abstract class AbstractBase{
        abstract getName():string
    
        printName(){
            console.log(this.getName());
            
        }
    }
    
    //const abst=new AbstractBase()//报错,无法创建抽象类的实例
    
    //想要调用抽象类的函数要再声明一个类来继承抽象类
    class ExtAbstract extends AbstractBase{
        getName(): string {
             return 'bunny'
        }
    }
    
    const abstract=new ExtAbstract()
    abstract.getName()
    abstract.printName()
    
    

    20

    class Xx {
        x: number = 2
        y: number = 3
    }
    class Yy {
        x: number = 24
        y: number = 34
    }
    
    const xy: Xx = new Yy()
    let x1 = xy.x = 88
    console.log(x1);
    
    

    相关文章

      网友评论

          本文标题:bunny笔记|TS基础(3):给类定义属性、构造函数、Gett

          本文链接:https://www.haomeiwen.com/subject/mresyrtx.html