TypeScript(十一) TS 中的类与 ES 标准的差异

TS 中的类与 ES 标准的差异

TS 中的类比 ES6 中多了修饰符概念

修饰符

public

public 表示公共的,用来指定在创建实例后可以通过实例来访问的,也就是类定义的外部可以访问的方法和属性

class Point {
  public x: number;
  public y: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
  public getPosition() {
    return `(${this.x}, ${this.y})`;
  }
}

private

private 修饰符表示私有的,他修饰的属性在类的定义外面是没法访问的,只能这个类内部自己玩

class Parent {
  private age: number;
  constructor(age: number) {
    this.age = age;
  }
}
const p = new Parent(18);
console.log(p); // { age: 18 }
console.log(p.age); // error 属性“age”为私有属性,只能在类“Parent”中访问
console.log(Parent.age); // error 类型“typeof ParentA”上不存在属性“age”
class Child extends Parent {
  constructor(age: number) {
    super(age);
    console.log(super.age); // 通过 "super" 关键字只能访问基类的公共方法和受保护方法
  }
}

protected

protected 和 private 有点相似,但是有一点不同,protected 修饰的成员在子类中可以访问,但是外部不行

class Parent {
  protected age: number;
  constructor(age: number) {
    this.age = age;
  }
  protected getAge() {
    return this.age;
  }
}
const p = new Parent(18);
console.log(p.age); // error 属性“age”为私有属性,只能在类“ParentA”中访问
console.log(Parent.age); // error 类型“typeof ParentA”上不存在属性“age”
class Child extends Parent {
  constructor(age: number) {
    super(age);
    console.log(super.age); // undefined
    console.log(super.getAge());
  }
}
new Child(18)
  • protected 还能用来修饰构造函数,加了 protected 之后这个类就不能创建实例
class Parent {
  protected constructor() {
    //
  }
}
const p = new Parent(); // error 类“Parent”的构造函数是受保护的,仅可在类声明中访问
class Child extends Parent {
  constructor() {
    super();
  }
}
const c = new Child();

readonly 修饰符

  • readonly 只读
class UserInfo {
  readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
}
const user = new UserInfo("Lison");
user.name = "haha"; // error Cannot assign to 'name' because it is a read-only property

访问构造函数里面的参数

  • 这样需要加上 public
class A {
  constructor(name: string) {}
}
const a = new A("aaa");
console.log(a.name); // error 类型“A”上不存在属性“name”
class B {
  constructor(public name: string) {}
}
const b = new B("bbb");
console.log(b.name); // "bbb"
  • 如果用了 private 则和前面一样
class Parent {
  public static getAge() {
    return Parent.age;
  }
  private static age: number = 18;
  constructor() {
    //
  }
}
const p = new Parent();
console.log(p.age); // error Property 'age' is a static member of type 'Parent'
console.log(Parent.age); // error 属性“age”为私有属性,只能在类“Parent”中访问

静态属性

  • 如果使用了 static 关键字来指定属性或者方法是静态的,实例将不会添加这个静态属性,也不会继承这个静态方法,你可以用修饰符和 static 关键字来指定一个属性或者方法
class Parent{
 public static age:number = 18;
 public static getAge(){
   return Parent.age;
 }
 constructor(){
   //构造函数
 }
  const p = new Parent();
  console.log(p.age); //error
  console.log(Parent.age); // 18
}
  • 如果使用了 private 修饰的话道理和前面一样
class Parent {
  public static getAge() {
    return Parent.age;
  }
  private static age: number = 18;
  constructor() {
    //
  }
}
const p = new Parent();
console.log(p.age); // error Property 'age' is a static member of type 'Parent'
console.log(Parent.age); // error 属性“age”为私有属性,只能在类“Parent”中访问。

可选类属性

  • 我们可以使用?来标记
class Info{
 name:string;
 age?:number;
 constructor(name:string,age?:number,sex?:string)
 {
   this.name = name;
   this.age = age
 }
 const info1 = new Info("lison");
 const info2 = new Info("lison",19);
 const info3 = new Info("lison",20,"man");
 //以上这些都没有问题
}

存取器

  • 他就是 ES6 中的存值函数和取值函数,在设置属性值的时候调用的函数, 和在访问属性值的时候调用的函数

class UserInfo{
  private _fullName:string;
  constructor(){}
  get fullName(){
    return this._fullName;
  }
  set fullName(value){
    console.log(`setter:${value}`);
    this._fullName = value;
  }
}
const user = new UserInfo();
user.fullName = "Lison"; // setter:Lison
console.log(user.fullName); // Lison

抽象类

  • 抽象类一般用来被其他类继承,而不是用于创建实例,抽象类和类内部定义抽象方法,使用 abstract 关键字
abstract class People {
  constructor(public name: string) {}
  abstract printName(): void;
}
class Man extends People {
  constructor(name: string) {
    super(name);
    this.name = name;
  }
  printName() {
    console.log(this.name);
  }
}
const m = new Man(); // error 应有 1 个参数,但获得 0 个
const man = new Man("lison");
man.printName(); // 'lison'
const p = new People("lison"); // error 无法创建抽象类的实例

在上面例子中我们定义了一个抽象类,在抽象类里面我们定义了 constructor 方法必须传入一个字符串类型参数,并且把这个 name 绑定在创建的实例上,使用 abstract 关键字来定义个抽象的方法 printName,这个定义可以指定参数,指定类型,指定返回类型等等。当我们直接使用抽象类 People 实例化的时候,就会报错。所以我们只能创建一个继承抽象类的子类

  • 抽象类中定义抽象方法,子类不会继承的,所以在子类中必须实现该方法的定义.
abstract class People {
  constructor(public name: string) {}
  abstract printName(): void;
}
class Man extends People {
  // error 非抽象类“Man”不会实现继承自“People”类的抽象成员"printName"
  constructor(name: string) {
    super(name);
    this.name = name;
  }
}
const m = new Man("lison");
m.printName(); // error m.printName is not a function

实例类型

  • 当我们定义了一个类,并创建实例后,这个实例的类型就是它创建的类

class People {
  constructor(public name: string) {}
}
let p: People = new People("lison");
  • 如果你想在定义一个和 People 类同样实现的类 Animal,并且创建实例
class Animal {
  constructor(public name: string) {}
}
let p = new Animal("lark");

对知识的补充

类继承接口

  • 类对类,接口对接口使用 extends!类继承接口,接口继承类必须用 implements 关键字
interface FoodInterface {
  type: string;
}
class FoodClass implements FoodInterface {
  // error Property 'type' is missing in type 'FoodClass' but required in type 'FoodInterface'
  static type: string
  constructor() {}
}

接口继承类

  • 接口可以继承一个类,当接口继承了该类之后,会继承类的成员。但是不包括其实现,也只是继承成员及其成员类型.接口还会继承类的 private 和 protected 成员.当接口继承的这个类中包含这两个修饰的成员,这个接口只可被这个类或者他的子类实现

class A {
  protected name: string;
}
interface I extends A {}
class B implements I {} // error Property 'name' is missing in type 'B' but required in type 'I'
class C implements I {
  // error 属性“name”受保护,但类型“C”并不是从“A”派生的类
  name: string;
}
class D extends A implements I {
  getName() {
    return this.name;
  }
}

在泛型中使用类类型

const create = <T>(c: { new(): T }): T => {
  return new c()
}
class Info {
  age: number
}
create(Info).age
create(Info).name // error 类型“Info”上不存在属性“name”

在这里我们创建了一个 create 函数,传入的参数是一个类,返回的是一个类创建的实例

  • 参数 c 的类型定义中,new()代表调用类的构造函数,他的类型就是类创建实例后的实例的类型

  • return new c()这里使用传进来的类 c 创建了一个实例并返回,返回的实例类型就是函数的返回值类型

  • 所以通过这个实例,调用 create 函数,传入和返回的值应该是同一个类类型。

总结

  • public 公共

  • private 私有,实例和子类都无法访问

  • protected 子类能访问,实例不能访问

  • readonly 只读,不能修改

  • abstract 抽象类,只能被继承不能被实例化

  • 类类型接口,接口继承类,泛型使用类


文章作者: 雾烟云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 雾烟云 !
  目录