TypeScript 中的 class
本文最后更新于:2022年4月22日 上午
TypeScript 中的 class
class 的基本使用
class Person {
name: string;
age: number; // 需要初始化值,否则 ts 检查报错
constructor(name: string, age: number) {
this.name = name; // 对于这种情况 Dart 中可以简写
this.age = age;
}
sayName() {
console.log(this.name);
}
}
const xiaomin = new Person('小明', 18);
xiaomin.name = '小东';
// xiaomin.age = 18;
xiaomin.sayName();
类的继承
一个类可以继承另外一个类,继承的类叫做 子类/派生类
,被继承的类叫做 父类/基类/超类
在 TypeScript
中 如果 子类
写了 构造函数
,则需要手动调用 super
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
}
class Man extends Person {
// constructor(name: string, age: number){
// super(name, age) // 如果写了构造函数,就需要手动调用 super();
// }
printSex() {
console.log('男生');
}
}
const man = new Man('小明', 18); //当子类没有构造函数的时,会自动调用父类的构造函数
man.printSex();
public、private、protected 可见性修饰符
public
public 对于类中的 成员/属性
,如果没有手动添加过 可见性修饰符,默认就是 public
class Person {
name: string;
// public name: string; 上述语法等同于该写法
constructor(name: string) {
this.name = name;
}
}
const person = new Person('小明');
console.log(person);
private
private
修饰的成员属性只能在类内部访问,子类和类的示例无法直接访问使用 ** private
修饰的成员属性或方法**
TypeScript
在类中声明的 private
只是编译阶段的 private
,如果强制忽略 TypeScript
的语法检测,子类和类的示例依旧可以访问到
class Person {
// 在 js 运行阶段时依旧可以获取到 prefix 属性,这是因为 JavaScript 并不支持真正意义的 private;
public name: string;
private nation = '中国';
constructor(name: string) {
this.name = name;
}
}
const person = new Person('小明');
// person.nation = '英国'; // ts 语法报错,运行阶段实际上是可以获取的
console.log(person);
protected
受保护的类型,使用protected
修饰的属性可以在子类中访问,但是实例上不可以访问
class Person {
public name: string;
protected sex: string = '男'; // protected 修饰的属性可以在子类中访问,但是实例上不可以访问
constructor(name: string) {
this.name = name;
}
}
class Man extends Person {
constructor(name: string) {
super(name);
}
saySex() {
console.log(this.sex); // 子类可以访问父类中用 protected 修饰的成员
}
}
const man = new Man('小明');
man.saySex(); // 男
// man.sex = 'woman'; // ts 语法报错,实例不能访问受保护的类型属性或方法
子类中如何获取 父类中的 私有属性
class Person {
public name: string;
private nation = '中国';
constructor(name: string) {
this.name = name;
}
getNation() {
return this.nation;
}
setNation(nation: string) {
this.nation = nation;
}
}
class Man extends Person {
printNation() {
console.log(this.getNation());
}
}
const man = new Man('小明');
// person.nation = '英国'; // ts 语法报错,运行阶段实际上是可以获取的
// man.printNation(); // 中国
// 通过调用子类中的方法来获取,或者实例也可以直接调用 getNation() 因为 该函数的声明是缺省的,默认是 public,如果将它的修饰符改为 protected 则实例无法调用
console.log(man.getNation());
readonly
类的成员属性可以加上 readonly
,一旦赋值后则无法再次修改
class Student {
name: string;
readonly grade: string;
// 如果 可见性修饰符 和 只读修饰符 同时出现,则 readonly 放在可见性修饰符后面
constructor(name: string, grade: string) {
this.name = name;
this.grade = grade;
}
}
const stu = new Student('小明', '1班');
console.log(`${stu.name}的班级为:${stu.grade}`);
// stu.grade = '2班'; // 无法分配到 "grade" ,因为它是只读属性
static 静态属性/方法
静态属性 和 方法 只能通过类去访问,不能通过类的实例去访问
class Student {
public static school = '希望小学';
}
// Student.school = '实验小学';
console.log(Student.school); // 实验小学
静态属性注意事项
因为覆盖 Function
上的属性和方法时不安全的,所以例如 name
,length
,call
,bind
等不能定位有静态属性
class Student {
// static name = 'hello'; // 静态属性“name”与构造函数“Student”的内置属性函数“name”冲突。ts(2699)
// static length = 10;
// static call = 'call';
}
class 中的 getter 和 getter
getter
和 setter
可以来截取我们队属性的获取和设置
需要注意以下几点
如果只写了
get
,没有写set
,则该属性为readonly
如果
set
的参数没有写类型注解,则会根据get
的返回值推导set
和get
的可见性修饰符必须一致,例如:不允许get
为public
,而set
为private
    
class Person {
_home = '';
public get home() {
return this._home;
}
public set home(value) {
this._home = value;
}
}
const person = new Person();
person.home = '成都';
console.log(person.home); // 成都
abstract 抽象类
抽象类中的 属性 或者 方法 可以 不包含具体的实现 ,交给子类来实现
抽象方法 或者 抽象属性 都是没有具体的实现,**且抽象类不能 ** new
由于抽象类不能 new
,所有一般 抽象类 是用来做一些基础逻辑的封装
abstract class Info {
abstract name: string; // 使用 abstract 修饰,子类必须实现
abstract sayName(): void; // 抽象类声明 函数和普通函数声明不太一致
sayHell() {
console.log('hello');
}
}
class Person extends Info {
name;
constructor(name: string) {
super();
this.name = name;
}
sayName() {
console.log(this.name);
}
}
// new Info(); // 语法报错,不允许 new 抽象类
const person = new Person('小明');
person.sayName();
person.sayHell();
声明类
如果我们想要限制 类的构造函数和实例类型,只通过一个 interface
显然是不够的,所以我们需要通过两个 interface
来声明类的类型
interface IPerson {
name: string;
age: number;
sayHello: () => void;
}
// 定义类的构造函数及其静态属性
interface IPersonClass {
new (name: string, age: number): IPerson;
ClassName: string;
}
// 通过双重约束来限制类的静态类型和类的实例类型
const PersonClass: IPersonClass = class Person implements IPerson {
name: string;
age: number;
static ClassName = 'person';
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("I' m " + this.name + ', hello');
}
};
const p = new PersonClass('小明', 18);
p.sayHello(); // I' m 小明, hello
构造函数简写方式
以上代码也可以简写成以下方式
interface IPerson {
name: string;
age: number;
sayHello: () => void;
}
// 定义类的构造函数及其静态属性
interface IPersonClass {
new (name: string, age: number): IPerson;
ClassName: string;
}
// 通过双重约束来限制类的静态类型和类的实例类型
const PersonClass: IPersonClass = class Person implements IPerson {
static ClassName = 'person';
// 会自动将传入的参数添加到 this
constructor(public name: string, public age: number) {}
sayHello() {
console.log("I' m " + this.name + ', hello');
}
};
const p = new PersonClass('小明', 18);
p.sayHello();
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处。