- 面向对象编程中一个重要的核心就是: 类 ,当我们使用面向对象的方式进行编程的时候,通常会首先去分析具体要实现的功能,把特性相似的抽象成一个一个的类,然后通过这些类实例化出来的具体对象来完成具体业务需求。
类的基础
- TypeScript 与 EMCAScript2015+ 在类方面共有的一些特性
- class 关键字
- 构造函数: constructor
- 成员属性定义
- 成员方法
- this关键字
- 除了以上的共同特性以外,在 TypeScript 中还有许多 ECMAScript 没有的,或当前还不支持的一些
特性,如:抽象
class
- 通过 class 就可以描述和组织一个类的结构,语法:
class User {
}
构造函数
- 通过 class 定义了一个类以后,我们可以通过 new 关键字来调用该类从而得到该类型的一个具体对
象:也就是实例化。 - 为什么类可以像函数一样去调用呢,其实我们执行的并不是这个类,而是类中包含的一个特殊函数:构造函数 -
constructor
class User {
constructor() {
console.log('实例化...')
}
}
let user1 = new User;
- 默认情况下,构造函数是一个空函数
- 构造函数会在类被实例化的时候调用
- 我们定义的构造函数会覆盖默认构造函数
- 如果在实例化(new)一个类的时候无需传入参数,则可以省略 ()
- 构造函数 constructor 不允许有 return 和返回值类型标注的(因为要返回实例对象)
- 通常情况下,我们会把一个类实例化的时候的初始化相关代码写在构造函数中,比如对类成员属性的初始化赋值
成员属性与方法定义
class User {
id: number;
username: string;
constructor(id: number, username: string) {
this.id = id;
this.username = username;
}
postArticle(title: string, content: string): void {
console.log(`发表了一篇文章: ${title}`)
}
}
let user1 = new User(1, 'xiaochen');
let user2 = new User(2, 'xiaoming');
this 关键字
- 在类内部,我们可以通过 this 关键字来访问类的成员属性和方法
class User {
id: number;
username: string;
postArticle(title: string, content: string): void {
console.log(`${this.username} 发表了一篇文章: ${title}`)
}
构造函数参数属性
- 因为在构造函数中对类成员属性进行传参赋值初始化是一个比较常见的场景,所以 ts 提供了一个简化
操作:给构造函数参数添加修饰符来直接生成成员属性 - public 就是类的默认修饰符,表示该成员可以在任何地方进行读写操作
class User {
constructor( public id: number, public username: string ) {
}
postArticle(title: string, content: string): void {
console.log(`${this.username} 发表了一篇文章: ${title}`)
}
}
let user1 = new User(1, 'xiaochen');
let user2 = new User(2, 'xiaoming');
继承
- 在 ts 中,也是通过 extends 关键字来实现类的继承
class VIP extends User {
}
super 关键字
- 在子类中,我们可以通过 super 来引用父类
- 如果子类没有重写构造函数,则会在默认的 constructor 中调用 super()
- 如果子类有自己的构造函数,则需要在子类构造函数中显示的调用父类构造函数 : super(//参 数) ,否则会报错
- 在子类构造函数中只有在 super(//参数) 之后才能访问 this
- 在子类中,可以通过 super 来访问父类的成员属性和方法
- 通过 super 访问父类的的同时,会自动绑定上下文对象为当前子类 this
class VIP extends User {
constructor( id: number, username: string, public score = 0 ) {
super(id, username);
console.log('子类构造函数');
}
postAttachment(file: string): void {
console.log(`${this.username} 上传了一个附件: ${file}`)
}
}
let vip1 = new VIP(1, 'Leo');
vip1.postArticle('标题', '内容');
vip1.postAttachment('1.png');
方法的重写与重载
- 默认情况下,子类成员方法集成自父类,但是子类也可以对它们进行重写和重载
- 重写
class VIP extends User {
constructor( id: number, username: string, public score = 0 ) {
super(id, username);
}
postArticle(title: string, content: string): void {
this.score++;
console.log(`${this.username} 发表了一篇文章: ${title},积分: ${this.score}`);
}
postAttachment(file: string): void {
console.log(`${this.username} 上传了一个附件: ${file}`)
}
}
let vip1 = new VIP(1, 'Leo');
vip1.postArticle('标题', '内容');
class VIP extends User {
constructor( id: number, username: string, public score = 0 ) {
super(id, username);
}
postArticle(title: string, content: string): void;
postArticle(title: string, content: string, file: string): void;
postArticle(title: string, content: string, file?: string) {
super.postArticle(title, content);
if (file) {
this.postAttachment(file);
}
}
postAttachment(file: string): void {
console.log(`${this.username} 上传了一个附件: ${file}`)
}
}
let vip1 = new VIP(1, 'xiaohong');
vip1.postArticle('标题', '内容');
vip1.postArticle('标题', '内容', '1.png');
修饰符
- 对类成员(属性、方法)进行一定的访问控制,来保证数据的安全,通过
类修饰 符
可以做到这一点目前 TypeScript 提供了四种修饰符:
- public:公有,默认
- protected:受保护
- private:私有
- readonly:只读
public 修饰符
protected 修饰符
private 修饰符
readonly 修饰符
- 只读修饰符只能针对成员属性使用,且必须在声明时或构造函数里被初始化,它的访问级别为:
class User {
constructor(
readonly id: number,
protected username: string,
private password: string ) {
}
}
let user1 = new User(1, 'zMouse', '123456');
寄存器
- 如果需要对类成员 属性 进行更加细腻的控制,就可以使用 寄存器 来完成这个需求,通过寄存器 ,可以对类成员属性的访问进行拦截并加以控制,更好的控制成员属性的设置和访问边界,寄存器分为种:
getter
setter- 组件
- 函数式组件
- 类式组件
- props 与 state
- 组件通信
- 表单与受控组件
设置控制器,当设置指定成员属性时调用
class User {
constructor(
readonly _id: number,
readonly _username: string,
private _password: string )
{
}
public set password(password: string) {
if (password.length >= 6) {
this._password = password;
}
}
public get password() {
return '******';
}
}
静态成员
- 前面说到的是成员属性和方法都是实例对象的,但是有的时候,需要给类本身添加成员,区分某成员是静态还是实例的:
- 该成员属性或方法是类的特征还是实例化对象的特征
- 如果一个成员方法中没有使用或依赖 this ,那么该方法就是静态的
type IAllowFileTypeList = 'png'|'gif'|'jpg'|'jpeg'|'webp';
class VIP extends User {
static readonly ALLOW_FILE_TYPE_LIST: Array<IAllowFileTypeList> = ['png','gif','jpg','jpeg','webp'];
constructor( id: number, username: string, private _allowFileTypes: Array<IAllowFileTypeList> ) {
super(id, username);
}
info(): void {
console.log(VIP.ALLOW_FILE_TYPE_LIST);
console.log(this._allowFileTypes);
}
}
let vip1 = new VIP(1, 'xiaochen', ['jpg','jpeg']);
console.log(VIP.ALLOW_FILE_TYPE_LIST);
this.info();
- 类的静态成员是属于类的,所以不能通过实例对象(包括 this)来进行访问,而是直接通过类名访
问(不管是类内还是类外) - 静态成员也可以通过访问修饰符进行修饰
- 静态成员属性一般约定(非规定)全大写