类的概念
类包含了一类事物的抽象特点,包含这类事物的属性和方法。
类的实现
传统方法中我们通过构造函数实现类的概念,在ES6中我们终于迎来了 class
,而 Typescript
除了实现ES6中的类的功能外,还添加了一些新的用法。
Typescript 中类的用法
属性和方法
使用 class
定义类,一个类可以包含以下几个成员
- 构造函数 Constructor
- 属性 Properties
- 方法 Methods
通过 new
生成实例的时候,会自动调用 constructor
。
class Animal {
public name;
constructor(name) {
this.name = name;
}
sayHi() {
return `My name is ${this.name}`;
}
}
let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
继承
使用关键字 extends
实现继承。
关于 super
:
- 在子类的
constructor
中,必须要使用super()
,他会调用父类的constructor
。 - 在子类中可以通过
super
来调用父类的方法。
class Animal {
public name;
constructor(name) {
this.name = name;
}
sayHi() {
return `My name is ${this.name}`;
}
}
class Human extends Animal {
constructor(name) {
super(name) // 调用父类的 constructor
}
sayMorning() {
console.log('moring')
console.log(super.sayHi()) // 调用父类的方法
}
}
const man = new Human('Andy')
man.sayMorning()
上述示例中,子类 Human
存在构造函数,必须要调用super
,调用的同时会触发父类的构造函数,因次如果父类的构造函数存在参数,super
的调用也需要传对应的参数。
在子类的方法 sayMorning
中,通过 super.sayHi()
调用了父类的 sayHi
修饰符
TypeScript 可以使用三种访问修饰符,分别是 public
、private
、protected
,默认为 public
。
public
修饰的属性或方法是公有的,可以在任何地方访问到。private
修饰的属性或方法是私有的- 不能在声明它的类的外部访问(实例和子类)
- 当构造函数修饰为 private 时,该类不允许被继承或实例化
protected
修饰的属性或方法是受保护的- 和
private
相似,但是可以在子类中访问。 - 当构造函数被修饰为protected时,该类不允许被实例化,但可以被继承。
- 和
public
class Animal {
public name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
public
描述的属性可以在实例中访问
private
- 私有属性无法在实例中访问
class Employee {
public name;
private salary=10000;
public constructor(name) {
this.name = name;
}
printSalary() {
return this.salary // Employee类中访问私有属性 salary 是 OK 的
}
}
let a = new Employee('Jack');
console.log(a.salary);
// Property 'salary' is private and only accessible within class 'Employee'.
a.salary = 100000;
// Property 'salary' is private and only accessible within class 'Employee'.
- 私有属性无法在子类中访问
class Employee {
public name;
private salary=10000;
public constructor(name) {
this.name = name;
}
printSalary() {
return this.salary
}
}
class Boy extends Employee{
public constructor(name) {
super(name)
console.log(this.salary)
//Property 'salary' is private and only accessible within class 'Employee'.
}
}
上述示例中,Boy
继承了 Employee
,在子类 Boy
中访问私有属性 salary
会出现错误提示。
- 当
constructor
被设置为private
后无法创建实例
class Employee {
private constructor(name) {
}
}
let a = new Employee('Jack');
// Constructor of class 'Employee' is private and only accessible within the class declaration.
提示 Employee
的构造函数是私有的,只能在类中使用。
protected
- 受保护的属性可以在子类中访问,但是无法通过实例访问
class Employee {
public name;
protected salary=10000;
public constructor(name) {
this.name = name;
}
printSalary() {
return this.salary
}
}
class Boy extends Employee{
public constructor(name) {
super(name)
console.log(this.salary) // 受保护属性在子类中可以访问
}
}
let a = new Employee('Jack');
console.log(a.salary)
// Property 'salary' is protected and only accessible within class 'Employee' and its subclasses.
- 构造函数被设置为受保护的属性后,无法创建实例
class Employee {
public name;
protected salary=10000;
protected constructor(name) {
this.name = name;
}
printSalary() {
return this.salary
}
}
let a = new Employee('Jack');
// Constructor of class 'Employee' is protected and only accessible within the class declaration.
readonly修饰符
readonly 即一旦创建,不能修改。但不影响初始化,在类中声明或构造函数中初始化是允许的、也是有必要的。
class Employee {
readonly empCode: number = 1; // Ok: declaration
readonly empName: string;
constructor(code: number, name: string) {
this.empName = name; // Ok: initialized inside the class constructor
}
}
let emp = new Employee(10, "John");
emp.empCode = 20;
// Error:Cannot assign to 'empCode' because it is a constant or a read-only property.
emp.empName = 'Bill';
// Error:Cannot assign to 'empName' because it is a constant or a read-only property.
注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。
class Animal {
public readonly name
public constructor(name) {
this.name = name;
}
}
参数属性
修饰符和 readonly
可以在构造函数参数中使用,等同于类中定义该属性的同时给该属性赋值,使代码更简洁
class Employee {
constructor(protected name='human') {
}
}
class Boy extends Employee{
getName() {
return this.name
}
}
let boy = new Boy()
console.log(boy.getName()) // human
静态属性
属性前加上static
关键字,就表示该属性不会被实例继承。
静态属性只能通过类来访问
class Animal {
static num = 42;
constructor() {
// ...
}
}
console.log(Animal.num); // 42
const cat = new Animal()
console.log(cat.num)
// Property 'num' is a static member of type 'Animal'
存取器
使用 getter
setter
可以改变属性的读取和赋值行为
可以防止我们意外的直接修改公有属性,并为我们检索和设置属性提供了更多控制。
class Person {
private _name: string = '';
get name(): string {
return this._name
}
set name(newName) {
alert(newName.length)
if (newName && newName.length < 5) {
throw new Error('Name is too short');
} else {
this._name=newName
}
}
}
let person = new Person()
person.name = 'Jane Smith'
console.log(person.name)
上述示例中,_name
为私有属性,通过 getter 的 name
获取 _name
的值,在 setter 中我们限制的name的赋值长度需大于 5,小于 5 的话抛出一个异常。
另外 只带有 get不带有 set的存取器自动被推断为 readonly
抽象类
abstract
用于定义抽象类和其中的抽象方法
抽象类有以下几个特点
- 抽象类不允许被实例化
- 抽象类通过子类来实现
- 抽象类方法和接口相似,只定义方法,不包含方法体
- 抽象类方法必须通过子类实现
抽象类不允许被实例化: 实例化一个抽象类会出现异常提示
abstract class Animal{
constructor(public name:string) {
this.name = name
}
}
const abstractAnimal = new Animal()
// Cannot create an instance of an abstract class.
抽象类通过子类来实现,子类继承了抽象类的属性和方法
class Cat extends Animal{
}
const cat = new Cat('miaomiao')
console.log(cat.name)
上述示例中,Cat
继承了抽象类 Animal
,并且能够拥有 Animal
的属性name
抽象类方法和接口相似,只定义方法,不包含方法体,并且必须通过子类实现。
abstract class Animal{
constructor(public name:string) {
this.name = name
}
abstract getName(){}
// Error: Method 'getName' cannot have an implementation because it is marked abstract.
}
class Cat extends Animal{
// Error: Non-abstract class 'Cat' does not implement inherited abstract member 'getName' from class 'Animal'.
}
上述示例抛出了两个异常:
- 抽象方法包含方法体后提示:
getName
为抽象类方法,不能被实现。 - 继承类没有实现抽象方法提示: 非抽象类
Cat
没有实现抽象类Animal
的方法getName
正确示例应为
abstract class Animal{
constructor(public name:string) {
this.name = name
}
abstract getName()
}
class Cat extends Animal{
getName() {
return this.name
}
}
const cat = new Cat('miaomiao')
console.log(cat.getName()) // miaomiao
类的类型
即类可以像接口一样作为类型描述
class Animal{
constructor(public name: string = 'animal') {
this.name = name
}
}
const animal:Animal = new Animal()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!