Typescript知识点 --- (5)类

1、es类 vs ts类
 
相同点:类成员的属性都是实例属性,而不是原型属性;类成员的方法都是原型方法
不同点:ts 中类成员的属性必须有初始值,或者是在构造函数中被初始化
class Dog {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
  run() {}
}

console.log(Dog.prototype);    // Dog { run: [Function] }

let dog = new Dog(‘Bob‘);
console.log(dog);             // Dog { name: ‘Bob‘ }

// name 属性只在实例上,不在原型上;run 方法只在原型上,不在实例上


2、类的继承
 
与es一样,ts中类的继承也是通过 extends 关键字,并且,在子类构造函数中,super关键字必须放在第一行

class Animal {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
}

class Dog extends Animal {
  constructor(name: string, leg: number) {
    super(name);
    this.leg = leg;
  }
  leg: number;
  intro() {
    console.log(`My name is ${this.name}, I hava ${this.leg} legs.`);
  }
}

let bob: Dog = new Dog(‘Bob‘, 4);
bob.intro();   // My name is Bob, I hava 4 legs.


3、成员修饰符
 
3-1、public
对所有人可见,在 ts 中,类的所有成员都默认为 public

class Animal {
  constructor(name: string) {
    this.name = name;
  }
  // 默认是public,可省略
  public name: string;
  public say () {
    console.log(‘hello... ...‘)
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}

let bob: Dog = new Dog(‘Bob‘);
bob.say();   // hello... ...


3-2、private
 
只能被类本身调用,不能被类的实例或者子类调用

class Animal {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
  private say () {
    console.log(‘hello... ...‘)
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}

// private 不能用于实例
let jorge: Animal = new Animal(‘Jorge‘);
jorge.say(); // Property ‘say‘ is private and only accessible within class ‘Animal‘.

// private 不能用于子类
let bob: Dog = new Dog(‘Bob‘);
bob.say();   // Property ‘say‘ is private and only accessible within class ‘Animal‘.
 
用于构造函数,则表示这个类既不能实例化,也不能被继承
class Animal {
  private constructor(name: string) {
    this.name = name;
  }
  name: string;
}

// Cannot extend a class ‘Animal‘. Class constructor is marked as private.
class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}

let a: Animal = new Animal(‘aaa‘);
// Constructor of class ‘Animal‘ is private and only accessible within the class declaration


3-3、protected
 
只能被类本身或者子类调用,不能被实例调用

class Animal {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
  protected say() {
    console.log(`hello ${this.name}`)
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
    this.say(); 
  }
}

let d: Dog = new Dog(‘ddd‘);     // hello ddd

let a: Animal = new Animal(‘aaa‘);
a.say();
// Property ‘say‘ is protected and only accessible within class ‘Animal‘ and its subclasses.
 
用于构造函数,表示这个类不能被实例化,只能被继承,相当于是声明了一个基类
class Animal {
  protected constructor(name: string) {
    this.name = name;
  }
  name: string;
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}

let d: Dog = new Dog(‘ddd‘); 

let a: Animal = new Animal(‘aaa‘);
// Constructor of class ‘Animal‘ is protected and only accessible within the class declaration.


3-4、readonly
 
只读属性必须在声明时或构造函数里被初始化,且不可更改

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  readonly name: string;
  readonly leg: number = 4;
}

let d: Dog = new Dog(‘Bob‘);
d.name = ‘Carl‘;  // Cannot assign to ‘name‘ because it is a read-only property.
d.leg = 2;  // Cannot assign to ‘leg‘ because it is a read-only property.


3-5、static
 
静态属性,只能通过类名来调用。调用方式是 类名.静态属性名,类的静态成员也可以被继承

class People {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
  static legs: number = 2; 
}

class Student extends People {
  constructor(name: string) {
    super(name);
  }
}

console.log(People.legs);   // 2
console.log(Student.legs);  // 2

构造函数的参数也可以添加修饰符,作用是将参数自动变成实例的属性,这样就不用在类中去定义参数了

class People {
  constructor( public name: string) {
    this.name = name;
  }
  // name: string;   // 标识符“name”重复
}


4、getter/setter 存取器
 
如果一个类没有使用存取器,那么,其成员属性是可以被随意修改的

class Dog {
  constructor(name: string) {
    this.name = name;
  }
  name: string;
  getName() {
    console.log("name: ", this.name);
  }
}

let d: Dog = new Dog(‘Bob‘);
d.name = ‘Carl‘;
d.getName();     // name:  Carl
 
而封装的基本原则是尽可能的隐藏内部实现细节,只保留一些对外接口使之与外部发生联系,这个时候就需要用到存取器了

class Dog {
  constructor() {}
  private _name: string;
  get name(): string {
    return this._name;
  }

  set name(name: string) {
    if(name.length > 10) {
      console.log(‘Error: the name is too long!‘)
    } else {
      this._name = name;
    }
  }
}

let d: Dog = new Dog();

d.name = ‘hello world!‘;  // Error: the name is too long!

console.log(d.name);   // undefined
d.name = ‘Bob‘;
console.log(d.name);   // Bob

相关推荐