持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
前言
我们在使用JavaScript开发时,使用函数和原型链继承可以创建复用性比较高的组件,但这并不符合面向对象的方式,面向对象是基于类的继承来实现的。ES6之后,JavaScript也能够基于类的面向对象方式进行开发。typescript在这方面也做了类型检查的支持,下面我们一起来看看吧。
类
- 类(Class) : 定义了一切事物的抽象特点
- 对象( Object) : 是类的实例,可以将类创建成具体的事物。
- 面向对象(OOP)编程的三大特性: 封装、继承、多态
- 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,
- 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性。
- 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。
封装
让我们先来封装一个类,在JavaScript中是这样定义的
// 封装
class Animal {
constructor(name) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
const snake = new Animal('lily');
上面我们定义了一个类,并且进行了实例化,这里面还没有添加类型检查,我们如何把类型检查添加上呢?
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
const snake = new Animal("lily");
我们对属性name做了类型检查,在typescript中,使用一个变量时需要对其做声明,或者标明是公共属性。这里定义的name: string就是在做变量声明,默认为公共属性,我们也可以改成下面的形式:
class Animal {
constructor(public name) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
const snake = new Animal('lily');
在构造函数中声明name是公共属性,就不会报错了。
继承
有的时候我们需要对现有的类做一些扩展,比如我们上面声明的Animal类,我想声明一个Dog类,它具备Animal的特性,但又有自己的特性,我们就需要使用继承了。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
class Dog extends Animal {
call() {
console.log('I am dog');
}
}
const dog = new Dog('lily');
dog.run();
dog.call()
公共,私有与受保护的修饰符
默认为public
我们刚刚提到了声明的name属性是公共属性,这个是默认属性,我们也可以明确标明哪些属性函数式公共的
class Animal {
public name: string;
public constructor(name: string) {
this.name = name;
}
public run() {
return `${this.name} is running`;
}
}
const snake = new Animal("lily");
私有属性 private
当我们有些属性或者方法不想让外部访问到,包括派生和实例化,可以标记为private
class Animal {
private name: string;
constructor(name: string) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
call() {
console.log(`I am ${this.name}`); // 派生类也会报错
}
}
const dog = new Dog('lily');
dog.run();
dog.call();
const snake = new Animal('lily');
snake.name; // 这里会报错
派生可访问protected
如果我们不想让实例化后被访问,但是想让继承派生的类能访问怎么办呢?这个时候我们可以使用protected来声明:
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
run() {
return `${this.name} is running`;
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
call() {
console.log(`I am ${this.name}`); // 这里可以访问
}
}
const dog = new Dog('lily');
dog.name; // 这里会报错
dog.run();
dog.call();
const snake = new Animal('lily');
snake.name; // 这里会报错
总结
以上介绍的内容足够我们应对基本的开发需求,官方文档上还有很多内容,我们可以用到的时候再做讲解。