持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
ES6新增了class关键字,类的概念。而类主要是实现了面向对象开发(其实我看好多文章说页面开发最好不要用class...),那么它就有属于面向对象开发的特点,而TS中的类的用法就又比JS中的更专业一点了,比如继承、封装、多态以及抽象、私有、公共等。
public、private 和 protected
在属性上
- public指的是公共的,可以被子类、自身或者实例访问到的;
- protected指的是受保护的,仅仅可以被子类或者自身访问到;
- private指的是私有的,也就是只能自己访问到;
class Person {
private features: string = "直立行走";
protected sex;
constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
let p = new Person('xiaolei',18,'男');
console.log(p.name,p.age);
console.log(p.sex); //报错:属性“sex”受保护,只能在类“Person”及其子类中访问。
console.log(p.features); //报错:属性“features”为私有属性,只能在类“Person”中访问。
在子类中:
class Person {
private features: string = "直立行走";
protected sex;
constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
console.log(this.features); //直立行走
}
}
class Man extends Person {
constructor(...args:any[]) {
super(...args as [string,number,string]);
console.log(this.sex);
console.log(this.name);
console.log(this.age);
console.log(this.features); //报错:属性“features”为私有属性,只能在类“Person”中访问。
}
}
let l = new Man('xiaolei',18,'男人');
在static上
但是我们要清楚这个private只能在自己访问到的意思是能在Class内部访问到,它还是添加在Person.prototype上面的,而不是直接加在Person上面,我们直接使用Person.reatures是获取不到的。想要通过Person.features获取到得使用static关键字(但是不能使用private关键字,不然还是)。
class Person {
static features: string = "直立行走";
constructor(public name: string) {
this.name = name;
console.log(this.features); //直立行走
}
}
console.log(Person.features); //报错:类型“typeof Person”上不存在属性“features”。
但是如果使用了private关键字修饰的话,那还是只能在Class内部使用:
class Person {
private static features: string = "直立行走";
constructor(public name: string) {
this.name = name;
console.log(Person.features); //直立行走
}
}
去掉private关键字(也就是使用public关键字)就可以在外部通过Person获取到了:
class Person {
static features: string = "直立行走";
constructor(public name: string) {
this.name = name;
}
}
console.log(Person.features);
在构造函数上
此外,private、protect和public还可以用在方法或者构造函数上(默认加的是public,就比如上面的例子默认函数其实加的就是public):
class Person {
private features: string = "直立行走";
protected sex;
protected constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
class Man extends Person {
constructor(...args:any[]) {
super(...args as [string,number,string]);
console.log(this.sex);
}
}
let l = new Man('xiaolei',18,'男人');
let x = new Person('xiaoxu',20,'女人');//报错:类“Person”的构造函数是受保护的,仅可在类声明中访问。
也就是说这个类只能被继承,却不能被实例化了。
如果是private,那么这个class就寄了,既不能被继承又不能被实例化了。
class Person {
private features: string = "直立行走";
protected sex;
private constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
class Man extends Person { //报错:无法扩展类“Person”。类构造函数标记为私有。
constructor(...args:any[]) {
super(...args as [string,number,string]);
console.log(this.sex);
}
}
let l = new Man('xiaolei',18,'男人');
let x = new Person('xiaoxu',20,'女人');//报错:类“Person”的构造函数是受保护的,仅可在类声明中访问。
在方法上
当然public就不说了,那是在哪里都可以访问,就相当于any一样,适用于任何情况!
class Person {
static features: string = "直立行走";
protected sex;
constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
console.log(Person.features);
}
protected sayName() {
console.log(this.name);
}
protected static sayFeatures() {
console.log(Person.features);
}
}
class Man extends Person {
constructor(...args:any[]) {
super(...args as [string,number,string]);
Person.sayFeatures();
this.sayName();
}
}
let l = new Man("xiaolei", 18, "男人");
console.log(Person.sayFeatures()); //报错:属性“sayFeatures”受保护,只能在类“Person”及其子类中访问。
如果是private呢?
class Person {
static features: string = "直立行走";
protected sex;
constructor(public name: string, public age: number, sex: string) {
this.name = name;
this.age = age;
this.sex = sex;
console.log(Person.sayFeatures());
console.log(this.sayName());
}
private sayName() {
console.log(this.name);
}
private static sayFeatures() {
console.log(Person.features);
}
}
class Man extends Person {
constructor(...args:any[]) {
super(...args as [string,number,string]);
Person.sayFeatures(); //报错:属性“sayFeatures”为私有属性,只能在类“Person”中访问。
this.sayName(); //报错:属性“sayName”为私有属性,只能在类“Person”中访问。
}
}
let l = new Man("xiaolei", 18, "男人");
console.log(Person.sayFeatures()); //报错:属性“sayFeatures”为私有属性,只能在类“Person”中访问。
那么这个方法就只能自己调用了,在子类或者实例上都不能使用。
abstract
用于定义抽象类和其中的抽象方法。
抽象类
抽象类是不允许被实例化的:
abstract class Person {
constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
}
let p = new Person("xiaolei", 18, "男人"); //报错:无法创建抽象类的实例。
那么抽象类就只能被继承咯,那么抽象类一般用来干嘛?一般抽象类就是用来声明抽象方法的。
抽象方法与多态
抽象方法只能在抽象类中被定义,抽象类中的方法只能声明不能实现,我们只能在继承抽象类的子类中去实现它且必须实现它。
abstract class Person {
constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
abstract sayName():void;
abstract sayAge():void;
}
class Man extends Person { //报错:非抽象类“Man”不会实现继承自“Person”类的抽象成员“sayAge”。
constructor(public name: string, public age: number) {
super(name,age);
}
sayName() {
console.log(this.name);
};
}
我们实现这个方法就好了:
abstract class Person {
constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
abstract sayName(): void;
abstract sayAge(): void;
}
class Man extends Person {
constructor(public name: string, public age: number) {
super(name, age);
}
sayName() {
console.log(this.name);
}
sayAge(): void {
console.log(this.age);
}
}
同时我们不同的子类去实现相同的方法,但是内容却不一样,每个子类有不同的表现。
readonly
只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。它的意思是这个值是只能get确不能set,就是只能读取,不能改变。
class Person {
readonly name;
constructor(name: string) {
this.name = name;
}
}
let l = new Person('xiaolei');
console.log(l.name);
l.name = 'xiaoxu'; //报错:无法分配到 "name" ,因为它是只读属性。
注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。
class Person {
// public readonly name;
public constructor(public readonly name) {
// this.name = name;
}
}
封装属性
下面我们就来说说类的封装(和JS的没啥区别)
class Person {
// 不允许直接访问该属性,命名上一般以下划线_开头
private _sex:string = 'male';
constructor(public name: string) {
this.name = name;
}
public set sex(v : string) {
if(v==='male' || v==='female') {
this._sex = v;
} else {
console.log('性别只能是male或者female')
}
}
public get sex() : string {
return this._sex;
}
}
let l = new Person('xiaolei', 'male');
console.log(l.sex); // male
l.sex = '男'; //性别只能是male或者female