TypeScript 专题之 Ts 中的类(class)
Posted 余光、
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript 专题之 Ts 中的类(class)相关的知识,希望对你有一定的参考价值。
在 ES6 中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。它本质仍然是函数,它让对象原型的写法更加清晰、更像面向对象编程的语法。
在 TypeScript 中,除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法。
这一节主要介绍类的用法,让我们平滑的从ES6过渡到Ts吧~
系列文章,收藏不走丢哦
一、什么是类
虽然 javascript 中有类的概念,但是可能大多数 JavaScript 程序员并不是非常熟悉类,毕竟大部分人使用它的频率并不高,所以我们来学一学类的基本使用。
- 类(Class):定义了一件事物的抽象特点,包含它的属性和方法
- 对象(Object):类的实例,通过 new 生成
1.1 属性和方法
使用 class 定义类,使用constructor
定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
class Male {
constructor(name) {
this.name = name;
}
getName() {
return `My name is ${this.name}`;
}
}
let man = new Male("余光");
console.log("man:", man.getName()); // My name is 余光
1.2 类的继承
使用extends
关键字实现继承,子类中使用super
关键字来调用父类的构造函数和方法。
class Animal {
constructor(name) {
this.name = name;
}
sayHi() {
console.log("hi");
}
}
class Cat extends Animal {
constructor(name) {
super(name); // 调用父类的constructor(name)
console.log(">>>:", this.name);
}
sayHi() {
return super.sayHi(); // 调用父类的 sayHi()
}
}
const cat = new Cat("余光"); // 余光
cat.sayHi(); // hi
1.3 存取器
使用 getter 和 setter 可以改变属性的赋值和读取行为:
class Animal {
constructor(name) {
this.name = name;
}
get name() {
return "Jack";
}
set name(value) {
console.log("setter: " + value);
}
}
let a = new Animal("Kitty"); // setter: Kitty
a.name = "Tom"; // setter: Tom
console.log(a.name); // Jack
1.4 实例属性
1.1 小节里,想要初始化就需要在 constructor 内进行定义,在 ES7 中可以直接在类里面定义:
class Animal {
name = "Jack";
constructor() {
// ...
}
}
let a = new Animal();
console.log(a.name); // Jack
1.5 静态属性
同样在ES7 提案中,可以使用static
定义一个静态属性:
class Animal {
static num = 42;
constructor() {
// ...
}
}
console.log(Animal.num); // 42
二、TypeScript 中的类
2.1 基本使用
下面看一个使用类的例子:
class Notice {
msg: string;
constructor(message: string) {
this.msg = message;
}
show() {
return this.msg;
}
}
const notice = new Notice("hi");
console.log(notice.show()); // hi
你会发现我指定了 msg 的类型,并进行赋值操作了。
2.2 继承
在 TypeScript 里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
看下面的例子:
class Animal {
type: string;
constructor(_type: string) {
this.type = _type;
}
intro() {
console.log(`I am a ${this.type}`);
}
}
class Dog extends Animal {
constructor(type: string) {
super(type);
}
sayHi() {
console.log("wang! wang!");
}
}
const dog = new Dog("dog");
dog.intro(); // I am a dog
dog.sayHi(); // wang wang
通过 extends 关键字。Dog
继承了Animal
的方法和属性
因为 Dog 继承了 Animal 的功能,因此我们可以创建一个 Dog 的实例,它能够intro()
和sayHi()
。
2.3 修饰符
TypeScript可以使用几种访问修饰符分别是:
- public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
- protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
- readonly 属性设置为只读的,只读属性必须在声明时或构造函数里被初始化。
理解public
在上面的例子里,我们可以自由的访问程序里定义的成员。就会注意到我们在之前的代码里并没有使用 public 来做修饰;
你也可以明确的将一个成员标记成 public。我们可以用下面的方式来重写上面的 Animal 类:
class Animal {
public type: string;
public constructor(_type: string) {
this.type = _type;
}
public intro() {
console.log(`I am a ${this.type}`);
}
}
理解private
当成员被标记成private
时,它就不能在声明它的类的外部访问。比如:
class Animal {
private name: string;
constructor(_name: string) {
this.name = _name;
}
sayHi(){
console.log(this.name)
}
}
const dog = new Animal('dog');
dog.name; // error: 属性“name”为私有属性,只能在类“Animal”中访问
理解 protected
protected 修饰符与 private 修饰符的行为很相似,但有一点不同,protected 成员在派生类中仍然可以访问。例如:
class Animal {
protected name: string;
constructor(_name: string) {
this.name = _name;
}
sayHi(){
console.log(this.name)
}
}
class Dog extends Animal {
name: string
constructor(name: string){
super(name)
}
}
const dog = new Dog('dog');
console.log('>>>', dog.name); // dog
注意,我们不能在Animal
类外使用name
,但是我们仍然可以通过Dog
类的实例方法访问,因为Dog
是由Animal
派生而来的。
理解readonly
你可以使用readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class Animal {
readonly name: string;
constructor(_name: string) {
this.name = _name;
}
}
let dad = new Animal("dog");
dad.name = "apples"; // error 无法分配到 "name" ,因为它是只读属性
2.4 存取器
和ES6中的一样,TypeScript同样支持通过getters/setters
来截取对对象成员的访问。
还是那个Animal类,我们循序渐进的添加get
和set
。
class Animal {
name: string;
}
let dog = new Animal();
dog.name = "柯基";
if (dog.name) {
console.log(dog.name);
}
上面的例子我们要加一个set和get:
class Animal {
private _name: string;
get name() {
return this._name;
}
set name(newName: string) {
if (newName === "柯基") {
this._name = newName;
} else {
this._name = "新用户";
}
}
}
let dog = new Animal();
dog.name = "小柯基";
console.log(dog.name); // 新用户
2.5 静态属性
到目前为止,我们只讨论了类的实例成员,那些仅当类被实例化的时候才会被初始化的属性,我们也可以创建类的静态成员,同样和ES6一样,我们来看一下:
class Dog {
static staticName = "dog";
getName(){
console.log(Dog.staticName)
}
}
Dog.staticName; // dog
new Dog().getName(); // dog
2.6 抽象类
抽象类做为其它派生类的基类使用。它们一般不会直接被实例化。不同于接口,抽象类可以包含成员的实现细节。
abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法。
abstract class Animal {
abstract makeSound(): void;
sayHi(): void {
console.log("Hi.");
}
}
// error
class Dog extends Animal {
// error 非抽象类“Dog”不会实现继承自“Animal”类的抽象成员“makeSound”
// 必须要对抽象类中的抽象方法进行实现,属性也是一样
}
// good
class Cat extends Animal {
makeSound() :void{
console.log('miao miao~');
}
}
const cat = new Cat();
cat.sayHi(); // hi
cat.makeSound(); // miao miao~
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。抽象方法的语法与接口方法相似。两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含abstract关键字并且可以包含访问修饰符。
2.7 把类当做接口使用
类定义会创建两个东西:
- 类的实例类型
- 一个构造函数
因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = { x: 1, y: 2, z: 3 };
写在最后
本篇文章是《Typescript入门首次》的第四篇文章,本篇文章主要聊一聊Ts中的类是什么样子的,旨在让我们在类这部分从ES6过渡到ts能更平滑一些,欢迎小伙伴们积极踊跃的互动,我会及时回复的哦,下一篇我们聊一聊由类衍生出来的专题《类与接口》
如果对你有帮助的话不妨收藏一下吧
系列文章传送门:
- 【Typescript入门手册】之基本类型在 TypeScript 中的应用
- 【Typescript入门手册】之引用类型在 TypeScript 中的应用
- 【Typescript入门手册】之函数类型在 TypeScript 中的应用
- 【Typescript专题】之类型进阶
- 【Typescript专题】之类型断言
- 本文
关于我
- 花名:余光
- WX:j565017805
- 邮箱:webbj97@163.com
其他沉淀
以上是关于TypeScript 专题之 Ts 中的类(class)的主要内容,如果未能解决你的问题,请参考以下文章