TypeScript 中的修饰符
什么是修饰符?
我们有办法让类中的属性变为只读的吗?
可以啊,在 TS 中只需要给属性加上 readonly 修饰符就可以了。
修饰符,什么是修饰符呢?
修饰符就是一些关键字,可以用来限定类的成员的性质,比如说常见的 public 用来表示共有的属性或者方法,那一共有多少中修饰符呢?
别急,我们一起来系统的学习下类的修饰符吧。
访问控制修饰符
class Cat { private name: string; constructor(name: string) { this.name = name; } // 使用访问控制修饰符 private sayHi(): string { return `Meow, my name is ${this.name}`; } } let tom = new Cat('Tom'); tom.name = 'Jack'; // 报错:属性“name”为私有属性,只能在类“Cat”中访问 // 如果改成 public 就不报错 // 如果改成 protected 的话,会报错:属性“name”受保护,只能在类“Cat”及其子类中访问 // 报错:属性“sayHi”为私有属性,只能在类“Cat”中访问 // 如果改成 public 就不报错 // 如果改成 protected 的话,会报错:属性“sayHi”受保护,只能在类“Cat”及其子类中访问 tom.sayHi(); 复制代码
区别
当前类 | 子类 | 实例 | |
---|---|---|---|
private | √ | ||
protected | √ | √ | |
public | √ | √ | √ |
习题:关于访问控制修饰符,下面用法错误的是?
// A class Animal { public age = 10; private getAge() { return this.age; } } new Animal().getAge(); // B class Animal { protected age = 10; public getAge() { return this.age; } } new Animal().getAge(); // C class Animal { private age = 10; protected getAge() { return this.age; } } new Animal().getAge(); // D class Animal { private age = 10; public getAge() { return this.age; } } new Animal().getAge(); 复制代码
答案:A C
解析:
private
- 被声明的属性(方法)为私有的属性(方法),只能在类 Animal
内部使用。
protected
- 被声明的属性(方法)为受保护的属性(方法),即可以在类 Animal
内部使用,也可以在子类中使用。
public
- 被声明的属性(方法)为共有的属性(方法),不仅在类 Animal
内部可以使用,也可以在子类和实例中使用。
A -
age
被修饰为public
,在getAge
方法中调用用法正确。getAge
被修饰为private
,在实例new Animal()
中调用用法错误。B -
age
被修饰为protected
,在getAge
方法中调用用法正确。getAge
被修饰为public
,在实例new Animal()
中调用用法正确。C -
age
被修饰为private
,在getAge
方法中调用用法正确。getAge
被修饰为protected
,在实例new Animal()
中调用用法错误。D -
age
被修饰为private
,在getAge
方法中调用用法正确。getAge
被修饰为public
,在实例new Animal()
中调用用法正确。
只读属性
class Cat { private readonly name: string; constructor(name: string) { this.name = name; } changeName(name: string) { this.name = name; // 报错:无法分配到“name”,因为它是常数或只读属性 } sayHi(): string { return `Meow, my name is ${this.name}`; } } let tom = new Cat('Tom'); tom.changeName('Jack'); 复制代码
资料:readonly vs const
在 TypeScript 中,const 是常量标志符,其值不能被重新分配(re-assignment)。
同时 TypeScript 的类型系统同样也允许将 interface、type、 class 上的属性标识为 readonly。
interface IUser { readonly name: string } type User = { readonly name: string } class Person { readonly name = 'Rich' } 复制代码
readonly 和 const 看起来做了同样的事情。但是他们其实并不相同,我们可以从这几个方面来区别:
readonly 实际上只是在编译阶段进行代码检查。而 const 则会在运行时检查(在支持 const 语法的 JavaScript 运行时环境中)。
readonly 是属性,而 const 是常量
习题:关于只读属性,下面用法错误的是?
// A class Animal { private readonly age = 10; public getAge() { return this.age; } } new Animal().getAge(); // B class Animal { public readonly age = 10; public getAge() { return this.age; } } new Animal().age; // C class Animal { readonly age: number = 10; constructor(age: number) { this.age = age; } } new Animal(20).age; // D class Animal { readonly age: number = 10; setAge(age: number) { this.age = age; } } new Animal().setAge(20); 复制代码
答案:D
解析:
readonly
只能用于修饰属性,不能用于修饰方法。被 readonly
修饰的属性只能初始化阶段赋值和 constructor
中赋值。其他任何方式的赋值都是不被允许的。
A -
age
被修饰为private readonly
,在getAge
方法中调用且未发生赋值操作用法正确。getAge
被修饰为public
,在实例中调用用法正确。B -
age
被修饰为public readonly
,未发生赋值操作用法正确。C -
age
被修饰为readonly
,在初始化阶段赋值和constructor
中赋值用法正确。D -
age
被修饰为readonly
,在setAge
方法中赋值用法错误。
静态属性
class Cat { // 猫能活的最长寿命 static maxAge = 38; static setMaxAge(age: number) { Cat.maxAge = age; } private name: string; constructor(name: string) { this.name = name; } sayHi(): string { return `Meow, my name is ${this.name}`; } } let tom = new Cat('Tom'); Cat.maxAge = 40; Cat.setMaxAge(50); 复制代码
习题:关于静态属性,下面用法正确的是?
// A class Animal { public static age = 10; public static getAge() { return this.age; } } Animal.getAge(); // B class Animal { public age = 10; public static getAge() { return this.age; } } Animal.getAge(); // C class Animal { public static age = 10; public getAge() { return this.age; } } new Animal.getAge(); // D class Animal { public static age = 10; public static getAge() { return Animal.age; } } Animal.getAge(); 复制代码
答案:A D
解析:
学习完属性和方法,我们知道类的属性默认是实例属性,类的方法默认是实例方法。
TypeScript
中提供了访问修饰符 static
用于定义类的静态属性和方法。静态属性和方法可直接通过类名访问,静态方法中只能访问静态属性和静态方法。
A -
getAge
被修饰为public static
,Animal.getAge()
调用是正确的。age
被修饰为public static
,在静态方法getAge
中调用静态属性age
是正确的,故本选项正确。B -
getAge
被修饰为public static
,Animal.getAge()
调用是正确的。age
被修饰为public
,在静态方法getAge
中调用实例属性age
是错误的。故本选项错误。C -
getAge
被修饰为public
,new Animal().getAge()
调用是正确的。age
被修饰为public static
,在实例方法getAge
中使用this.age
是错误的。故本选项错误D -
getAge
被修饰为public static
,Animal.getAge()
调用是正确的。age
被修饰为public static
,在静态方法getAge
中调用静态属性age
是正确的,故本选项正确。
抽象类
abstract class Animal { name: string; /* abstract sayHi(): string { // 报错:方法“sayHi”不能具有实现,因为它标记为抽象 return "Hi"; } */ abstract sayHi(): string } let animal = new Animal(); // 报错:无法创建抽象类的实例。 class Cat extends Animal { sayHi() { return `Meow, my name is ${this.name}`; } } class Dog extends Animal { // 报错:非抽象类“Dog”不会实现继承自“Animal”类的抽象成员“sayHi” sayHi() { return "Hi"; } } 复制代码
修饰符总结
名称 | 描述 |
---|---|
访问控制修饰符 | private,protected,public |
只读属性 | readonly |
静态属性 | static |
抽象类、抽象方法 | abstract |
习题:关于抽象类,下面用法正确的是?
// A abstract class Animal { public age = 10; public getAge() { return this.age; } } new Animal().getAge(); // 报错:无法创建抽象类的实例 // B abstract class Animal { public age = 10; public abstract getAge(): number; } class Panda extends Animal { public getAge() { return this.age; } } new Panda().getAge(); // C abstract class Animal { public age = 10; public abstract getAge(): number; } class Panda extends Animal { // 报错:非抽象类“Panda”不会实现继承自“Animal”类的抽象成员“getAge” public setAge(age: number) { return this.age = age; } } new Panda().setAge(20); // D abstract class Animal { public age = 10; public abstract setAge(age: number): void; } class Panda extends Animal { // 报错 public setAge(age: string) { this.age = age; } } new Panda().setAge('20'); /* 报错: 类型“Panda”中的属性“setAge”不可分配给基类型“Animal”中的同一属性。 不能将类型“(age: string) => void”分配给类型“(age: number) => void”。 参数“age”和“age” 的类型不兼容。 不能将类型“number”分配给类型“string”。 */ 复制代码
答案:B
解析:
被 abstract
修饰的类为抽象类,在抽象类中被 abstract
修饰的方法为抽象方法。抽象类不能被实例化,抽象类中的抽象方法必须被子类实现。本例中使用 extends
继承了父类 Animal
(下章节介绍类继承相关知识)
选项中的 Animal
为抽象类
A - 抽象类不能被实例化,故错误。
B - 子类
Panda
继承于抽象类Animal
并实现了抽象方法getAge
,用法正确。C - 子类
Panda
继承于抽象类Animal
,但是未实现抽象方法getAge
,故错误。D - 抽象类
Animal
中的抽象方法setAge
的函数类型为public setAge(age: number): void
,而子类实现的setAge
的函数类型为public setAge(age: string): void
,与抽象类所定义的函数类型不相符,故错误。
作者:追梦玩家
链接:https://juejin.cn/post/7031450398959337486