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