Skip to content
Created: October 5, 2020

class ​

1. How to define a class ​

  • "strictPropertyInitialization": true // Enable strict checking of class property initialization
  • name!:string
ts
class Person {
  name: string;
  getName(): void {
    console.log(this.name);
  }
}
let p1 = new Person();
p1.name = "hello ";
p1.getName();
ts
/**
 * 当我们写一个类的时候,会得到2个类型
 * 1. 构造函数类型的函数类型
 * 2. 类的实例类型
 */
class Component {
  static myName: string = "静态名称属性";
  myName: string = "实例名称属性";
}
let com = Component;
//Component类名本身表示的是实例的类型
//ts 一个类型 一个叫值
//冒号后面的是类型
//放在=后面的是值
let c: Component = new Component();
let f: typeof Component = com;

2. accessor ​

  • In TypeScript, we can use accessors to change the reading and assignment behavior of properties in a class
  • Constructor
    • Mainly used to initialize member variable attributes of the class
    • Automatically called and executed when the object of the class is created
    • no return value
ts
class User {
  myname: string;
  constructor(myname: string) {
    this.myname = myname;
  }
  get name() {
    return this.myname;
  }
  set name(value) {
    this.myname = value;
  }
}

let user = new User("hello ");
user.name = "jiagou";
console.log(user.name);
ts
"use strict";
var User = /** @class */ (function () {
  function User(myname) {
    this.myname = myname;
  }
  Object.defineProperty(User.prototype, "name", {
    get: function () {
      return this.myname;
    },
    set: function (value) {
      this.myname = value;
    },
    enumerable: true,
    configurable: true,
  });
  return User;
})();
var user = new User("hello ");
user.name = "jiagou";
console.log(user.name);

3. Parameter properties ​

ts
class User {
  constructor(public myname: string) {}
  get name() {
    return this.myname;
  }
  set name(value) {
    this.myname = value;
  }
}

let user = new User("hello ");
console.log(user.name);
user.name = "jiagou";
console.log(user.name);

4. readonly ​

  • Variables modified with readonly can only be initialized in the constructor
  • In TypeScript, const is a constant identifier whose value cannot be reassigned
  • TypeScript's type system also allows properties on interface, type, and class to be marked as readonly
  • readonly actually just does code checking during the compilation phase.And const will be checked at runtime (in a JavaScript runtime environment that supports const syntax)
ts
class Animal {
  public readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
  changeName(name: string) {
    this.name = name;
  }
}

let a = new Animal("hello ");
a.changeName("xiaoming");

5. inheritance ​

  • After the subclass inherits the parent class, the instances of the subclass will have the attributes and methods in the parent class, which can enhance the reusability of the code.
  • Abstract the methods common to the subclass and put them in the parent class, and put your own special logic in the subclass and override the logic of the parent class.
  • super can call methods and properties on the parent class
ts
class Person {
  name: string; // 定义实例的属性,默认省略public修饰符
  age: number;
  constructor(name: string, age: number) {
    // 构造函数
    this.name = name;
    this.age = age;
  }
  getName(): string {
    return this.name;
  }
  setName(name: string): void {
    this.name = name;
  }
}
class Student extends Person {
  no: number;
  constructor(name: string, age: number, no: number) {
    super(name, age);
    this.no = no;
  }
  getNo(): number {
    return this.no;
  }
}
let s1 = new Student("hahaha ", 10, 1);
console.log(s1);

6. Modifiers inside the class ​

ts
class Father {
  public name: string; //类里面 子类 其它任何地方外边都可以访问
  protected age: number; //类里面 子类 都可以访问,其它任何地方不能访问
  private money: number; //类里面可以访问, 子类和其它任何地方都不可以访问
  constructor(name: string, age: number, money: number) {
    //构造函数
    this.name = name;
    this.age = age;
    this.money = money;
  }
  getName(): string {
    return this.name;
  }
  setName(name: string): void {
    this.name = name;
  }
}
class Child extends Father {
  constructor(name: string, age: number, money: number) {
    super(name, age, money);
  }
  desc() {
    console.log(`${this.name} ${this.age} ${this.money}`);
  }
}

let child = new Child("hahaha ", 10, 1000);
console.log(child.name);
console.log(child.age);
console.log(child.money);

7. static properties static methods ​

ts
class Father {
  static className = "Father";
  static getClassName() {
    return Father.className;
  }
  public name: string;
  constructor(name: string) {
    //构造函数
    this.name = name;
  }
}
console.log(Father.className);
console.log(Father.getClassName());

8. Decorator ​

  • A decorator is a special type of declaration that can be attached to a class declaration, method, property, or parameter to modify the behavior of the class
  • Common decorators include class decorators, property decorators, method decorators and parameter decorators
  • The writing methods of decorators are divided into ordinary decorators and decorator factories.
ts
class Person {
  say() {
    console.log("hello");
  }
}

function Person() {}
Object.defineProperty(Person.prototype, "say", {
  value: function () {
    console.log("hello");
  },
  enumerable: false,
  configurable: true,
  writable: true,
});

8.1 Class Decorators ​

  • Class decorators are declared before the class declaration and are used to monitor, modify or replace the class definition.
ts
namespace a {
  //当装饰器作为修饰类的时候,会把构造器传递进去
  function addNameEat(constructor: Function) {
    constructor.prototype.name = "hello ";
    constructor.prototype.eat = function () {
      console.log("eat");
    };
  }
  @addNameEat
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}

namespace b {
  //还可以使用装饰器工厂
  function addNameEatFactory(name: string) {
    return function (constructor: Function) {
      constructor.prototype.name = name;
      constructor.prototype.eat = function () {
        console.log("eat");
      };
    };
  }
  @addNameEatFactory("hello ")
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}

namespace c {
  // 还可以替换类,不过替换的类要与原类结构相同
  function enhancer(constructor: Function) {
    return class {
      name: string = "xiaoming";
      eat() {
        console.log("吃饭饭");
      }
    };
  }
  @enhancer
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}

8.2 Property decorators ​

  • The property decorator expression will be called as a function at runtime, passing in the following two parameters
  • Property decorators are used to decorate properties
    • The first parameter is the constructor of the class for static members and the prototype object of the class for instance members.
    • The second parameter is the name of the attribute
  • Method decorators are used to decorate methods
    • The first parameter is the constructor of the class for static members and the prototype object of the class for instance members.
    • The second parameter is the name of the method
    • The third parameter is the method descriptor
ts
namespace d {
  //修饰实例属性
  function upperCase(target: any, propertyKey: string) {
    let value = target[propertyKey];
    const getter = function () {
      return value;
    };
    // 用来替换的setter
    const setter = function (newVal: string) {
      value = newVal.toUpperCase();
    };
    // 替换属性,先删除原先的属性,再重新定义属性
    if (delete target[propertyKey]) {
      Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true,
      });
    }
  }
  //修饰实例方法
  function noEnumerable(
    target: any,
    property: string,
    descriptor: PropertyDescriptor,
  ) {
    console.log("target.getName", target.getName);
    console.log("target.getAge", target.getAge);
    descriptor.enumerable = true;
  }
  //重写方法
  function toNumber(
    target: any,
    methodName: string,
    descriptor: PropertyDescriptor,
  ) {
    let oldMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      args = args.map((item) => parseFloat(item));
      return oldMethod.apply(this, args);
    };
  }
  class Person {
    @upperCase
    name: string = "hello ";
    public static age: number = 10;
    constructor() {}
    @noEnumerable
    getName() {
      console.log(this.name);
    }
    @toNumber
    sum(...args: any[]) {
      return args.reduce((accu: number, item: number) => accu + item, 0);
    }
  }
  let p: Person = new Person();
  for (let attr in p) {
    console.log("attr=", attr);
  }
  p.name = "jiagou";
  p.getName();
  console.log(p.sum("1", "2", "3"));
}

8.3 Parameter decorator ​

  • It will be called as a function at runtime. You can use parameter decorators to add some metadata to the prototype of the class.
    • The first parameter is the constructor of the class for static members, and the prototype object of the class for instance members.
    • The name of the second parameter
    • The index of the third parameter in the function list
ts
namespace d {
  interface Person {
    age: number;
  }
  function addAge(target: any, methodName: string, paramsIndex: number) {
    console.log(target);
    console.log(methodName);
    console.log(paramsIndex);
    target.age = 10;
  }
  class Person {
    login(username: string, @addAge password: string) {
      console.log(this.age, username, password);
    }
  }
  let p = new Person();
  p.login("hello ", "123456");
}

8.4 Decorator execution order ​

  • When there are multiple parameter decorators: execute from the last parameter forward.
  • Parameter decorators in methods and method parameters are executed first.
  • Class decorators are always executed last
  • Method and property decorators, whichever comes first will be executed first.Because the parameters are part of the method, the parameters will always be executed next to the method.
  • Analogous to componentDidMount of React components: first up and then down, first inside and then outside.
ts
namespace e {
  function Class1Decorator() {
    return function (target: any) {
      console.log("类1装饰器");
    };
  }
  function Class2Decorator() {
    return function (target: any) {
      console.log("类2装饰器");
    };
  }
  function MethodDecorator() {
    return function (
      target: any,
      methodName: string,
      descriptor: PropertyDescriptor,
    ) {
      console.log("方法装饰器");
    };
  }
  function Param1Decorator() {
    return function (target: any, methodName: string, paramIndex: number) {
      console.log("参数1装饰器");
    };
  }
  function Param2Decorator() {
    return function (target: any, methodName: string, paramIndex: number) {
      console.log("参数2装饰器");
    };
  }
  function PropertyDecorator(name: string) {
    return function (target: any, propertyName: string) {
      console.log(name + "属性装饰器");
    };
  }

  @Class1Decorator()
  @Class2Decorator()
  class Person {
    @PropertyDecorator("name")
    name: string = "hello ";
    @PropertyDecorator("age")
    age: number = 10;
    @MethodDecorator()
    greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) {}
  }
}
/**
name属性装饰器
age属性装饰器
参数2装饰器
参数1装饰器
方法装饰器
类2装饰器
类1装饰器
 */

9. abstract class ​

  • Abstraction describes an abstract concept that cannot be instantiated and can only be inherited.
  • Unable to create instance of abstract class
  • Abstract methods cannot be implemented in abstract classes, they can only be implemented in concrete subclasses of abstract classes, and they must be implemented
ts
abstract class Animal {
  name!: string;
  abstract speak(): void;
}
class Cat extends Animal {
  speak() {
    console.log("喵喵喵");
  }
}
let animal = new Animal(); //Cannot create an instance of an abstract class
animal.speak();
let cat = new Cat();
cat.speak();
access control modifiersprivate protected public
Read-only propertiesreadonly
static propertiesstatic
abstract class, abstract methodabstract

10. abstract method ​

  • Abstract classes and methods do not contain concrete implementations and must be implemented in subclasses
  • Abstract methods can only appear in abstract classes
  • Subclasses can implement different implementations of abstract classes
ts
abstract class Animal {
  abstract speak(): void;
}
class Dog extends Animal {
  speak() {
    console.log("小狗汪汪汪");
  }
}
class Cat extends Animal {
  speak() {
    console.log("小猫喵喵喵");
  }
}
let dog = new Dog();
let cat = new Cat();
dog.speak();
cat.speak();

11. Override vs overload ​

  • Overriding means that a subclass overrides a method inherited from a parent class
  • Overloading refers to providing multiple type definitions for the same function
ts
class Animal {
  speak(word: string): string {
    return "动作叫:" + word;
  }
}
class Cat extends Animal {
  speak(word: string): string {
    return "猫叫:" + word;
  }
}
let cat = new Cat();
console.log(cat.speak("hello"));
//--------------------------------------------
function double(val: number): number;
function double(val: string): string;
function double(val: any): any {
  if (typeof val == "number") {
    return val * 2;
  }
  return val + val;
}

let r = double(1);
console.log(r);

12. Inheritance vs polymorphism ​

  • Inheritance (Inheritance) subclass inherits the parent class. In addition to having all the characteristics of the parent class, the subclass also has some more specific characteristics.
  • Polymorphism (Polymorphism) produces different related classes through inheritance, which can have different behaviors for the same method.
ts
class Animal {
  speak(word: string): string {
    return "Animal: " + word;
  }
}
class Cat extends Animal {
  speak(word: string): string {
    return "Cat:" + word;
  }
}
class Dog extends Animal {
  speak(word: string): string {
    return "Dog:" + word;
  }
}
let cat = new Cat();
console.log(cat.speak("hello"));
let dog = new Dog();
console.log(dog.speak("hello"));