TypeScript -- ts的类

TS的类

在传统的JavaScript中,我们使用构造函数来实现类的概念,通过原型链的方式来实现继承。值得庆祝的是,终于我们等来了ES6,迎来了class关键字。熟悉ES6的前端工程师肯定对此关键字不陌生,在TS中,对此部分进行了扩展,增加了许多新东西。

类的定义

我们使用class关键字来定义一个类,我们可以给类添加属性和方法。

class Person {
    name: string
    age: number

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
    }
}

const p1 = new Person("xiaoming", 21);
p1.sayHello();

上面代码中,我们定义了一个Person类,里面有name, age俩个属性,constructor, sayHello俩个方法。我们通过new Person(...)生成了一个对象p1,我们调用sayHello方法,打印了个人信息。
这是一个简单的类,为我们展示了TS中类的基础使用。

类的继承

在ES6中,我们使用extends关键字来实现继承。在TS中,我们同样这么做。

class Person {
    name: string
    age: number

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
    }
}

class Student extends Person {
    stuId: string

    constructor(name: string, age: number, stuId: string) {
        super(name, age);
        this.stuId = stuId;
    }
    sayHello() {
        super.sayHello();
        console.log("I am a student!");
    }
}

const s1 = new Student("xiaoming", 21, "W12138");
s1.sayHello();

我在刚刚Person类的基础上面,通过继承方式实现了Student类,并且还增加了一个新属性stuId
在Student构造函数中,使用super(…)调用父类的构造函数,我们还在Student类里面重写了sayHello方法,里面通过super.sayHello()调用父类的sayHello.
我们使用继承,提高了代码的利用率,我们不必重复写一些冗余代码,在设计模式中有重要的地位。

访问修饰符

访问修饰符是JavaScript没有的,所以我们详细介绍一下。
在TS中,总共有三种访问修饰符,protected private public

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
  • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

public
我们先来介绍最简单的public

class Person {
    public name: string
    public age: number

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
    }
}

我给name,age属性前面加上了public访问属性关键字,其实不加的默认值也是它
public name: stringname: string等价

const p1 = new Person("cyl",  21);
console.log(p1.name);

因为name,age的访问属性是public的,所以我们可以在外面直接通过实例.属性名来访问。
现在想想前面的代码,我们为什么p1.sayhello ,new Person()可以这样使用了?聪明的你,一定想到了吧!那是因为sayHello和constructor的访问属性是public的。

private
private私有的,有一款手机游戏的英雄(吕布+皮肤特性)的大致台词是:

貂蝉私有变量,谁敢访问,提头来见。

class Person {
    private name: string
    public age: number

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    sayHello() {
        console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
    }
}

const p1 = new Person("cyl",  21);
console.log(p1.name);

我们将name的访问属性改成private,那么我们在外面访问name属性时
在这里插入图片描述
说的非常清楚了,只允许在Person中访问,其子类也不行的,更别说外部了。

    private constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

我们给构造器加上private访问属性,我们还能在外面通过new运算符生成实例吗?
在这里插入图片描述
也是不行的。

protected
protectedprivate一样同样是为了限制用户访问权限的,但是protected的要求低一点,子类可以访问。

class Person {
    name: string
    age: number

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    protected sayHello() {
        console.log(`Hello, I am ${this.name}, ${this.age} years old.`);
    }
}

class Student extends Person {
    stuId: string

    constructor(name: string, age: number, stuId: string) {
        super(name, age);
        this.stuId = stuId;
    }
    sayHello() {
        super.sayHello();
        console.log("I am a student!");
    }
}

const s1 = new Student("xiaoming", 21, "W12138");
s1.sayHello();

const p1 = new Person("cyl",  21);
p1.sayHello();

我们给Person类里面的sayHello方法加上了protected访问属性,在Student类里面重写sayHello方法时使用了父类的sayHello方法,这样并没有问题,但是我们通过new Person(...)生成实例调用sayHello方法时报错了。
在这里插入图片描述

存取器

TS的存取器类似JS使用Object.defineProperty设置setter,getter。当用户需要对对象属性的赋值取值操作进行额外处理的时候,可以借助存取器。

class Person {
    firstName: string
    lastName: string
    private _fulllName: string

    constructor(fn: string, ln: string) {
        this.firstName = fn;
        this.lastName = ln;
    }
    get fullName () {
        this._fulllName = this.firstName + this.lastName;
        return this._fulllName;
    }
    set fullName (name: string) {
        let arr: string[] = name.split(" ");
        this.firstName = arr[0];
        this.lastName = arr[1];

    }
}

const p = new Person("c", "yl");
console.log(p.fullName);
p.fullName = "xiao ming"
console.log(p.firstName, p.lastName);

虽然这个例子可能不是很恰当,但是我们能够认识到get,set存取器的用法了。当我们使用实例.fullName时实际上调用的get fullName函数,同样的使用实例.fullName = '....'时实际调用的是set fullName(...)

静态属性

在TS中,我们可以通过static关键字来声明静态属性或者静态方法,这些属性方法并不是在实例对象上面而是在类本身上面。

class Person {
    firstName: string
    lastName: string

    static Id: number = 666

    constructor(fn: string, ln: string) {
        this.firstName = fn;
        this.lastName = ln;
    }

    static getId () {
        return Person.Id;
    }
}

console.log(Person.getId())

我们直接使用Person.getId()调用了Person对象上面的静态方法,而在方法里面使用一个静态属性Id
我们成功的打印了666。
这里有俩个问题,你仔细想一想

  • 假如把getId方法里面的Person.Id换成this.Id你觉得可行吗?
  • 如果我想使用Person.firstName你觉得这样可行吗?
    第一个问题其实不难,其实就是this的指向问题Person.getId()这样调用,this指向的依然是Person这个对象,所以没有什么问题。
    那么额外想一想这个问题
 class Person {
    firstName: string
    lastName: string

    static Id: number = 666

    constructor(fn: string, ln: string) {
        this.firstName = fn;
        this.lastName = ln;
    }

    static getId () {
        return this.Id;
    }
}
const f = Person.getId;
 console.log(f());

getId函数里面使用this,然后按照如下方法调用,会打印什么?想想呗!

第二个问题使用Person.firstName会报错的,因为firstName是类的实例部分,在没有通过new运算符生成实例对象之前这些实例部分是不存在的。
在这里插入图片描述

抽象类

这应该是本小节最后一个内容了,也是非常重要的一个内容的。
abstract关键字(抽象)

abstract class Animal {
    eat () {
        console.log("我能吃!")
    }
    abstract bark(): void
}

class Dog extends Animal {
    bark () {
        console.log("汪汪汪");
    }
}

class Cat extends Animal {
    bark () {
        console.log("喵喵喵");
    }
}

const d = new Dog();
d.bark();

const c = new Cat();
c.bark();

我们定义了一个抽象类Animal它含有一个eat方法和一个抽象方法bark,注意这个bark方法只是声明并没有实现。
DogCat类都继承于Animal类。因为继承于抽象类的缘故,我们在子类里面必须要重写实现父类定义的抽象方法。
还有一点值得注意的是:抽象类是不可以通过new运算符生成实例的。
ok,类的知识就介绍到这里了,下一节我们将一起学习函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值