阅读 185

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 staticAnimal.getAge() 调用是正确的。age 被修饰为 public static,在静态方法 getAge 中调用静态属性 age 是正确的,故本选项正确。

  • B - getAge 被修饰为 public staticAnimal.getAge() 调用是正确的。age 被修饰为 public,在静态方法 getAge 中调用实例属性 age 是错误的。故本选项错误。

  • C - getAge 被修饰为 publicnew Animal().getAge() 调用是正确的。age 被修饰为 public static,在实例方法 getAge 中使用 this.age 是错误的。故本选项错误

  • D - getAge 被修饰为 public staticAnimal.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


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐