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

简介: 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.



后言

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


目录
相关文章
|
6天前
|
JavaScript
​​​​Typescript 接口 和继承 数组处理
ts的基础数据类型,可用来处理一般数据,但是碰到后台传入的复杂对象数组的时候,我们可以使用ts中的接口来定义处理
32 0
|
6天前
|
JavaScript 前端开发 安全
ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争
ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争
|
6天前
|
JavaScript 编译器
TypeScript中泛型在函数和类中的应用
【4月更文挑战第23天】TypeScript的泛型在函数和类中提供了灵活性,允许处理多种数据类型。了解泛型是掌握TypeScript类型系统的关键。
|
6天前
|
JavaScript
类和继承在TypeScript中的使用详解
【4月更文挑战第23天】TypeScript中的类和继承详解:使用`class`定义类,包含属性和方法,如`Animal`示例。通过`extends`实现继承,如`Dog`继承`Animal`,可重写父类方法。使用访问修饰符`public`、`protected`、`private`控制成员可见性。抽象类和抽象方法用于定义基类和强制子类实现特定方法,提升代码组织和可维护性。
|
6天前
|
JavaScript
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
46 0
|
6天前
|
存储 设计模式 JavaScript
TypeScript 类的基础:从定义到实例化,让你快速掌握(三)
TypeScript 类的基础:从定义到实例化,让你快速掌握
|
6天前
|
存储 JavaScript
TypeScript 类的基础:从定义到实例化,让你快速掌握(二)
TypeScript 类的基础:从定义到实例化,让你快速掌握
|
6天前
|
缓存 JavaScript 前端开发
TypeScript 类的基础:从定义到实例化,让你快速掌握(一)
TypeScript 类的基础:从定义到实例化,让你快速掌握
|
6天前
|
JavaScript
如何在 TypeScript 中定义类
如何在 TypeScript 中定义类
20 0
|
6天前
|
JavaScript 前端开发 编译器
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
28 0