TypeScript 中的类使用
传统方法中,JavaScript 通过构造函数实现类的概念,通过原型链实现继承。而在 ES6 中,我们终于迎来了 class
。
TypeScript 除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法。
类的概念
虽然 JavaScript 中有类的概念,但是可能大多数 JavaScript 程序员并不是非常熟悉类,这里对类相关的概念做一个简单的介绍。
- 类(Class):定义了一件事物的抽象特点,包含它的属性和方法 对象(Object):类的实例,通过
new
生成。 - 面向对象(OOP)的三大特性:封装、继承、多态。
- 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据。
- 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性。
- 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如
Cat
和Dog
都继承自
Animal
,但是分别实现了自己的eat
方法。此时针对某一个实例,我们无需了解它是Cat
还是Dog
,就可以直接调用eat
。
方法,程序会自动判断出来应该如何执行eat
。 - 存取器(getter & setter):用以改变属性的读取和赋值行为。
- 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如
public
表示公有属性或方法。 - 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现。
- 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口。
属性和方法
使用 class 定义类,使用 constructor 定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
// 类:描述了所创建的对象共同的属性和方法。
// 通过类可以实例化对象
class Person {
name: string
age: number
// 构造器函数
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHi(str: string) {
console.log(`hi :${str}`)
}
}
let p = new Person('我是ed.', 25) // 在new的时候,会执行类中的构造方法。
p.sayHi("我是ed.")
类的继承
使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法。
// 定义为父类
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHi(str: string) {
console.log("hi " + str + "!")
}
}
// 定义为子类
class Dog extends Animal {
constructor(name: string, age: number) {
// 调用父类的构造函数
super(name, age);
}
sayHi(str: string) {
console.log("dog " + str + "!")
}
}
const cat = new Animal("小猫", 10);
cat.sayHi("小猫");
const dog = new Dog("小狗", 5);
dog.sayHi("我是一只小狗")
编译完成,查看运行结果:
注意,我们可以通过 super.sayHi("狗子")
直接调用父类的方法。
总结:
- 类与类之间存在继承关系,通过
extends
进行继承。 - 子类可以调用父类的方法,通过
super
。 - 子类可以重写父类的方法。
存取器
使用 getter
和 setter
可以改变属性的赋值和读取行为:
// 使用 getter 和 setter 可以改变属性的赋值和读取行为
class Name {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// 设置存取器
// 读取器 用来读取数据
get fullName() {
// 姓名 = 姓氏 + 名字
return this.firstName + ' ' + this.lastName;
}
// 设置器 用来设置数据
set fullName(name) {
this.firstName = name;
}
}
const n = new Name('我是', 'ed.');
console.log(n.fullName);
n.fullName = '我是谁';
console.log(n.fullName);
看一下打印的结果:
静态成员
静态成员包含静态属性和静态方法,只属于类自己的属性和方法。
使用 static
修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:
// 静态方法 + 静态属性
class A {
static name1: string // 静态属性
static sayHi() { // 静态方法
console.log('hi')
}
}
A.sayHi() // 静态方法
const a1 = new A()
a1.sayHi()
这时候发现,ts 编译器会报错:
修饰符
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public
、private
和 protected
。
- public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
- protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
public 公有
public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的。
// ** public ** 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
class B {
public name: string // 表示公有的属性
public constructor(name: string) {
this.name = name
}
public p() { // 表示公有的方法
console.log(this.name)
}
}
其实对于 public
而言,写不写都一样,因为不写的话,默认就是 public
。
所以上面的代码和下面的性质是一模一样的:
class B {
name: string
constructor(name: string) {
this.name = name
}
p() {
console.log(this.name)
}
}
private 私有
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问。
class B {
private name: string
constructor(name: string) {
this.name = name // name 设置为私有的,只能在类内部访问
}
p() {
console.log(this.name)
}
}
const b1 = new B('我是ed.')
console.log(b1.name) // 报错
b1.p()
我们声明了私有属性,在外部不能访问,所以说 console.log(b1.name)
会报错,和 java 一样是吧?
那现在出现一个问题啊,就是我在类B里面写了一个私有属性,那么如果有一个类C,继承B的话,他可以访问吗?试一下:
class B {
private name: string
constructor(name: string) {
this.name = name // name 设置为私有的,只能在类内部访问
}
p() {
console.log(this.name)
}
}
// const b1 = new B('我是ed.')
// console.log(b1.name) // 报错
// b1.p()
class C extends B{
constructor(name: string) {
super(name) // 继承父类的属性
}
}
const c = new C('我是ed.')
console.log(c.name) // 报错
我们可以看到,报错了:
所以:子类你可以继承私有属性和私有方法, 但是你不可以访问。
哪怕去类C里面的方法打印一下都不可以:
class C extends B{
constructor(name: string) {
super(name) // 继承父类的属性
}
p() {
console.log(this.name) // 报错
}
}
依旧是报错的:
protected 受保护
protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
上面我们看到了,private
修饰后,子类就算继承了也不可以访问,但是我们想子类可以访问但是外部依旧不能访问,这个时候就需要 protected
了。
class B {
protected name: string
constructor(name: string) {
this.name = name // name 设置为私有的,只能在类内部访问
}
p() {
console.log(this.name)
}
}
class C extends B {
constructor(name: string) {
super(name) // 继承父类的属性
}
p() {
console.log(this.name) // 不报错
}
}
const c = new C('我是ed.')
console.log(c.name) // 报错
这个时候呢,子类可以访问但是外部依旧不能访问:
可以看到,在子类可以继承且访问,但是在外部是不可以访问的。
readonly
只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。
class X {
readonly age:number // 表示该属性只读,但是在构造函数中是可以修改的
constructor(age:number) {
this.age = age
}
update() {
this.age = 18 // 报错,不能够被修改,因为只读
}
}
const x = new X(18)
console.log(x.age)
x.age = 20 // 报错,不允许被修改,因为只读
readonly
表示只读,除了在声明类的构造函数中允许修改外,其他位置均不可以修改:
如果我们的三个 修饰符 和 readonly 定义在参数上面,那么他会创建并且初始化参数:
// readonly
class X {
readonly age:number // 表示该属性只读,但是在构造函数中是可以修改的
constructor(readonly age:number) {
this.age = age
}
update() {
this.age = 18 // 报错,不能够被修改,因为只读
}
}
const x = new X(18)
console.log(x.age)
x.age = 20 // 报错,不允许被修改,因为只读
看,报错了!
抽象类 abstract
abstract
用于定义抽象类和其中的抽象方法。
什么是抽象类?
首先,抽象类是不允许被实例化的:
// 抽象类
abstract class A {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
let a = new A('Jack');
看,直接实例化一个抽象类,直接报错,告诉我们不允许:
上面的例子中,我们定义了一个抽象类 Animal,并且定义了一个抽象方法 sayHi。在实例化抽象类的时候报错了。
其次,抽象类中的抽象方法必须被子类实现:
// 抽象类
abstract class A {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
class C extends A {
public eat() {
console.log(`${this.name} is eating.`);
}
}
let c = new C('Tom');
上面的例子中,我们定义了一个类 Cat 继承了抽象类 Animal,但是没有实现抽象方法 sayHi,所以编译报错了。
下面是一个正确使用抽象类的例子:
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
class Cat extends Animal {
public sayHi() {
console.log(`Meow, My name is ${this.name}`);
}
}
let cat = new Cat('Tom');
上面的例子中,我们实现了抽象方法 sayHi,编译通过了。
标签:TypeScript,console,name,age,class,使用,public,string From: https://www.cnblogs.com/wjw1014/p/17928389.html