TypeScript 类 第一章【类,继承,修饰符】

前言

hello world欢迎来到前端的新世界


😜当前文章系列专栏:Typescript
🐱‍👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误,感谢大家指出)🌹
💖感谢大家支持!您的观看就是作者创作的动力

传统的JavaScript的程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript的版本。

下面看一个使用类的例子:

class Greeter {<font></font>
    greeting: string;
    constructor(message: string) {
        this.greeting = message;<font></font>
    }<font></font>
    greet() {<font></font>
        return "Hello, " + this.greeting;<font></font>
    }<font></font>
}<font></font>
<font></font>
let greeter = new Greeter("world");

如果你使用过C#或Java,你会对这种语法非常熟悉。我们声明一个 Greeter类。这个类有3个成员:一个叫做greeting的属性,一个构造函数和一个greet方法。

你会注意到,我们在引用任何一个类成员的时候都用了this。它表示我们访问的是类的成员。

最后一行,我们使用new构造了Greeter类的一个实例。它会调用之前定义的构造函数,创建一个 Greeter类型的新对象,并执行构造函数初始化它。


继承

在TypeScript里,我们可以使用常用的面向对象模式。当然,基于类的程序设计中最基本的模式是允许使用继承来扩展现有的类。

看下面的例子:

class Animal {<font></font>
    name:string;
    constructor(theName: string) { this.name = theName; }<font></font>
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);<font></font>
    }<font></font>
}<font></font>
<font></font>
class Snake extends Animal {
    constructor(name: string) { super(name); }<font></font>
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);<font></font>
    }<font></font>
}<font></font>
<font></font>
class Horse extends Animal {
    constructor(name: string) { super(name); }<font></font>
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);<font></font>
    }<font></font>
}<font></font>
<font></font>
let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");<font></font>
<font></font>
sam.move();<font></font>
tom.move(34);

这个例子展示了TypeScript中继承的一些特征,它们与其它语言类似。 我们使用 extends关键字来创建子类。你可以看到Horse和Snake类是基类Animal的子类,并且可以访问其属性和方法。

包含构造函数的派生类必须调用super(),它会执行基类的构造方法。

这个例子演示了如何在子类里可以重写父类的方法。 Snake类和Horse类都创建了move方法,它们重写了从Animal继承来的move方法,使得move方法根据不同的类而具有不同的功能。 注意,即使 tom被声明为Animal类型,但因为它的值是Horse,tom.move(34)会调用Horse里的重写方法:

Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.

公共,私有与受保护的修饰符

默认为public

在上面的例子里,我们可以自由的访问程序里定义的成员。 如果你对其它语言中的类比较了解,就会注意到我们在之前的代码里并没有使用 public来做修饰;例如,C#要求必须明确地使用public指定成员是可见的。 在TypeScript里,成员都默认为 public。

你也可以明确的将一个成员标记成public。 我们可以用下面的方式来重写上面的 Animal类:

class Animal {
    public name: string;
    public constructor(theName: string) { this.name = theName; }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);<font></font>
    }<font></font>
}<font></font>

理解private

当成员被标记成private时,它就不能在声明它的类的外部访问。比如:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // Error: 'name' is private;

TypeScript使用的是结构性类型系统。 当我们比较两种不同的类型时,并不在乎它们从何处而来,如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。

然而,当我们比较带有private或protected成员的类型的时候,情况就不同了。 如果其中一个类型里包含一个 private成员,那么只有当另外一个类型中也存在这样一个private成员, 并且它们都是来自同一处声明时,我们才认为这两个类型是兼容的。 对于 protected成员也使用这个规则。

下面来看一个例子,更好地说明了这一点:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }<font></font>
}<font></font>
<font></font>
class Rhino extends Animal {
    constructor() { super("Rhino"); }<font></font>
}<font></font>
<font></font>
class Employee {
    private name: string;
    constructor(theName: string) { this.name = theName; }<font></font>
}<font></font>
<font></font>
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");<font></font>
<font></font>
animal = rhino;<font></font>
animal = employee; // Error: Animal and Employee are not compatible

这个例子中有AnimalRhino两个类,RhinoAnimal类的子类。 还有一个 Employee类,其类型看上去与Animal是相同的。 我们创建了几个这些类的实例,并相互赋值来看看会发生什么。 因为 AnimalRhino共享了来自Animal里的私有成员定义private name: string,因此它们是兼容的。 然而 Employee却不是这样。当把Employee赋值给Animal的时候,得到一个错误,说它们的类型不兼容。 尽管 Employee里也有一个私有成员name,但它明显不是Animal里面定义的那个。

理解protected

protected修饰符与private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问。例如:

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }<font></font>
}<font></font>
<font></font>
class Employee extends Person {
    private department: string;<font></font>
<font></font>
    constructor(name: string, department: string) {
        super(name)
        this.department = department;<font></font>
    }<font></font>
<font></font>
    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;<font></font>
    }<font></font>
}<font></font>
<font></font>
let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error

注意,我们不能在Person类外使用name,但是我们仍然可以通过Employee类的实例方法访问,因为Employee是由Person派生而来的。

构造函数也可以被标记成protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承。比如,

class Person {
    protected name: string;
    protected constructor(theName: string) { this.name = theName; }<font></font>
}<font></font>
<font></font>
// Employee can extend Person
class Employee extends Person {
    private department: string;<font></font>
<font></font>
    constructor(name: string, department: string) {
        super(name);
        this.department = department;<font></font>
    }<font></font>
<font></font>
    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;<font></font>
    }<font></font>
}<font></font>
<font></font>
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected

readonly修饰符

你可以使用readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

class Octopus {<font></font>
    readonly name: string;<font></font>
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;<font></font>
    }<font></font>
}<font></font>
let dad = new Octopus("Man with the 8 strong legs");<font></font>
dad.name = "Man with the 3-piece suit"; // error! name is readonly.


后言

创作不易,要是本文章对广大读者有那么一点点帮助 不妨三连支持一下,您的鼓励就是博主创作的动力

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鋜斗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值