A, classes,

An important core of object-oriented programming is: class, when we use object-oriented programming, usually first to analyze the specific functions to achieve, the characteristics of similar abstract into a class, and then through these classes instantiated out of the specific object to complete the specific business needs.

[1] the basis of class

The basics of classes include the following core concepts that TypeScript shares with EMCAScript2015+ classes

  • classThe keyword
  • Constructor:constructor
  • Member attribute definition
  • Members of the method
  • This keyword

In addition to these common features, there are many other features in TypeScript that ECMAScript does not have or that are not currently supported, such as abstraction

【2】 Class keyword

Class describes and organizes the structure of a class.

Class User {// The characteristics of the class are defined inside {}}Copy the code

[3] constructor

Once a class is defined by class, we can call that class with the new keyword to get a concrete object of that type: instantiation. Why can a class be called like a function when we execute not this class but a special function contained within it: constructor-constructor

Class User {constructor() {console.log(' instantiate... ') } } let user1 = new User;Copy the code
  • By default, the constructor is an empty function

  • The constructor is called when the class is instantiated

  • The constructor we define overrides the default constructor

  • If you do not need to pass in an argument when instantiating (new) a class, omit ()

  • The constructor does not allow a return or return value type annotation (because an instance object is to be returned).

Typically, we write the initialization code for a class instantiation in the constructor, such as initialization assignments to class member attributes

[4] Member attributes and method definitions

class User { id: number; username: string; constructor(id: number, username: string) { this.id = id; this.username = username; } postArticle(title: string, content: string): Void {console.log(${title} ')}} let user1 = new User(1, 'Demi'); let user2 = new User(2, 'Davi');Copy the code

【5】 This keyword

Inside a class, we can access its member attributes and methods using the this keyword

class User { id: number; username: string; postArticle(title: string, content: string): Console. log(' ${this.username} ') {console.log(' ${this.username} ')}}Copy the code

[6] Constructor parameter properties

Because pass-parameter assignment initialization of class member attributes in constructors is a common scenario, TS provides a simplified operation: add modifiers to constructor parameters to generate member attributes directly

  • publicIs the default modifier of the class, indicating that the member can be read or written from anywhere
Class User {constructor(public id: number, public username: string) {// postArticle(title: String, content: string): void {console.log(' ${this.username} ')}} let user1 = new User(1, 'Demi'); let user2 = new User(2, 'Davi');Copy the code

Second, inheritance,

In TS, class inheritance is also implemented through the extends keyword

class VIP extends User {

}

Copy the code

[1] Super keyword

In subclasses, we can refer to the parent class by super

  • If the subclass does not override the constructor, super() is called from the default constructor

  • If the subclass has its own constructor, it needs to call the superclass constructor: super(// argument) as shown in the subclass constructor, otherwise an error will be reported

  • This is only accessible after super(// argument) in the subclass constructor

  • In subclasses, you can access the member properties and methods of the parent class through super

  • When accessing the parent class through super, the context object is automatically bound to the current subclass this

class VIP extends User { constructor( id: number, username: string, public score = 0 ) { super(id, username); } postAttachment(file: string): Void {console.log(' ${this.username} ')}} let vip1 = new VIP(1, 'Demi'); Vip1.postarticle (' title ', 'content '); vip1.postAttachment('1.png');Copy the code

[2] Method rewriting and overloading

By default, subclass member methods are integrated from the parent class, but they can also be overridden and overridden by subclasses

class VIP extends User { constructor( id: number, username: string, public score = 0 ) { super(id, username); } // postArticle(title: string, content: string): void {this.score++; Console. log(' ${this.username} '); } postAttachment(file: string): Void {console.log(' ${this.username} ')}} let vip1 = new VIP(1, 'Demi'); Vip1.postarticle (' title ', 'content ');Copy the code
class VIP extends User { constructor( id: number, username: string, public score = 0 ) { super(id, username); } // Number of arguments, different parameter types: overloaded postArticle(title: string, content: string): void; postArticle(title: string, content: string, file: string): void; postArticle(title: string, content: string, file? : string) { super.postArticle(title, content); if (file) { this.postAttachment(file); } } postAttachment(file: string): Void {console.log(' ${this.username} ')}} let vip1 = new VIP(1, 'Demi'); Vip1.postarticle (' title ', 'content '); Vip1.postarticle (' title ', 'content ', '1.png');Copy the code

3. Modifiers

Sometimes we want some control over class members (properties, methods) to keep data safe. Class modifiers do this. TypeScript provides four modifiers:

  • Public: public, default
  • Protected: Protected
  • Private: private
  • Readonly: read-only

[1] public modifier

This is the default modifier for a class member, and its access level is:

  • Their own
  • A subclass
  • Outside the class

[2] protected modifier

Its access level is:

  • Their own
  • A subclass

[3] private modifier

Its access level is:

  • Their own

[4] Readonly modifier

Read-only modifiers can only be used for member attributes and must be initialized at declaration time or in a constructor. They have access levels of:

  • Their own
  • A subclass
  • Outside the class
Class User {constructor(// accessible but cannot modify readonly id: number, // accessible but cannot externally modify protected username: Private password: string) {//... } / /... } let user1 = new User(1, 'Demi', '123456');Copy the code

4. Register

Sometimes, we need more delicate control of class member attributes, we can use registers to complete this demand, through registers, we can intercept and control the access to class member attributes, better control the setting of member attributes and access boundaries, registers are divided into two types:

  • getter
  • setter

【 1 】 the getter

Access controller, called when accessing specified member properties

[2] Setters – components

  • Functional component

  • The component class type

  • Props and state

  • Component communication

  • Forms and controlled components

Set controller, called when specified member properties are set

class User {

    constructor(
  	  readonly _id: number,
      readonly _username: string,
      private _password: string
    ) {
    }

    public set password(password: string) {
        if (password.length >= 6) {
            this._password = password;
        }
    }

    public get password() {
        return '******';
    }
  	// ...
}

Copy the code

Static members

Member properties and methods belong to instance objects, but sometimes we need to add members to the class itself to distinguish whether a member is static or instance:

  • The characteristics of the member property or method type are also characteristics of the instantiated object
  • If there are no uses or dependencies in a member methodthis, then the method is static
type IAllowFileTypeList = 'png'|'gif'|'jpg'|'jpeg'|'webp'; Class VIP extends User {// static readonly ALLOW_FILE_TYPE_LIST: Array<IAllowFileTypeList> = ['png','gif','jpg','jpeg','webp']; constructor( id: number, username: string, private _allowFileTypes: Array<IAllowFileTypeList> ) { super(id, username); } info(): void {// Static members of the class use the class name. Static members to access // VIP this type of users are allowed to upload all types of which there are some console.log(vip.allow_file_type_list); // What console.log(this._allowFileTypes) is currently allowed for this VIP user; } } let vip1 = new VIP(1, 'Demi', ['jpg','jpeg']); // Static members of a class use the class name. Static members to access console.log(VIp.allow_file_type_list); this.info();Copy the code
  • Static members of a class belong to the class, so they are not accessed through instance objects (including this), but directly through the class name (either inside or outside the class)
  • Static members can also be decorated with access modifiers
  • Static member attributes are generally (but not always) capitalized

6. Abstract classes

Sometimes, methods of a base class (parent class) do not determine the specific behavior, but are implemented by inheriting subclasses, see the following example:

Nowadays, componentized front-end designs are popular, such as React

class MyComponent extends Component { constructor(props) { super(props); this.state = {} } render() { //... }}Copy the code

Based on the above code, we can roughly design the following class structure

  • One for each componentpropsProperty, which can be initialized by a constructor, and is defined by the parent
  • One for each componentstateProperty defined by the parent
  • There must be one for each componentrenderThe method of
class Component<T1, T2> { public state: T2; constructor( public props: T1 ) { // ... } render(): string { // ... }} Interface IMyComponentProps {title: string;}} Interface IMyComponentProps {title: string; } interface IMyComponentState { val: number; } class MyComponent extends Component<IMyComponentProps, IMyComponentState> { constructor(props: IMyComponentProps) { super(props); this.state = { val: 1 } } render() { this.props.title; this.state.val; Return '<div> component </div>'; }}Copy the code

The render method of the parent class is a bit awkward, but we should have constrained the subclass to have the render method, otherwise the code will not pass

[1] Abstract keywords

If a method has no concrete implementation method, it can be decorated with the abstract keyword

abstract class Component<T1, T2> {

    public state: T2;

    constructor(
        public props: T1
    ) {
    }

    public abstract render(): string;
}

Copy the code

There is one benefit to using abstract classes:

The convention of all inherited subclasses must implement the method, so that the design of the class more standard

Precautions for use:

  • Methods modified by abstract cannot have a method body
  • If a class has abstract methods, that class must also be abstract
  • If a class is abstract, it cannot be instantiated using new (because the class has unimplemented methods, instantiation is not allowed)
  • If a subclass inherits from an abstract class, it must implement all the abstract methods in the abstract class, or else the class must be declared abstract

Classes and interfaces

Previously we have looked at the use of interfaces, through which we can define a structure and contract for objects. We can also combine interfaces with classes to enforce contracts through interfaces. In some ways, when there is only abstraction in an abstract class, it is not much different from interfaces. In this case, we prefer to define contracts through interfaces

  • Abstract classes still generate entity code when compiled, whereas interfaces do not
  • TypeScriptOnly single inheritance is supported, that is, a subclass can have only one parent class, but a class can implement an interface
  • Interfaces cannot have implementations; abstract classes can

【 1 】 implements

Using an interface in a class does not use the extends keyword, but implements

  • Similar to an interface, if a classimplementsAn interface, then the contract defined in that interface must be implemented
  • Use multiple interfaces.separated
  • implements 与 extendsCoexisting
interface ILog { getInfo(): string; } class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog { constructor(props: IMyComponentProps) { super(props); this.state = { val: 1 } } render() { this.props.title; this.state.val; Return '<div> component </div>'; } getInfo() {return 'component: MyComponent, props: ${this.props}, state: ${this.state}'; }}Copy the code

Implementing multiple interfaces

interface ILog { getInfo(): string; } interface IStorage { save(data: string): void; } class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog, IStorage { constructor(props: IMyComponentProps) { super(props); this.state = { val: 1 } } render() { this.props.title; this.state.val; Return '<div> component </div>'; } getInfo(): string {return 'Component: MyComponent, props: ${this.props}, state: ${this.state}'; } save(data: string) { // ... Storage}}Copy the code

Interfaces can also be inherited

interface ILog {
    getInfo(): string;
}
interface IStorage extends ILog {
    save(data: string): void;
}

Copy the code

Classes and object types

When we define a class in TypeScript, we are defining two different types

  • Class type (constructor type)
  • Object type

First, the object type is easy to understand, which is the instance type that comes out of our new

What is that type? We know that a class in JavaScript or a class in TypeScript is essentially a function, and of course we call it a constructor, so the class or the constructor itself has a type, so that type is the type of the class

Class Person {// Static type = 'Person '; // Name of the instance: string; age: number; gender: string; / / class constructor is also belongs to the class constructor (name: string, age, number, gender: 'male' | 'female' = 'male') {enclosing name = name; this.age = age; this.gender = gender; } public eat(): void { // ... }} let p1 = new Person('Demi', 24, 'female '); p1.eat(); Person.type;Copy the code

In the example above, there are two different pieces of data

  • PersonClass (constructor)
  • throughPersonInstantiated objectp1

There are also two different types

  • Type of instance (Person)
  • Constructor type (typeof Person)

The interface is described as follows

interface Person { name: string; age: number; gender: string; eat(): void; } interface PersonConstructor {/ / new said it is a new constructor (name: string, age, number, gender: 'male' | 'female') : PersonInstance; type: string; }Copy the code

Be careful when using it

Function fn1(arg: Person /* If you want the Person instance passed here */) {arg.eat(); } fn1(new Person('', 1, 'male ')); Function fn2(arg: typeof Person /* If you want to pass the Person constructor */) {new arg(", 1, 'male '); } fn2(Person);Copy the code

The article is updated every week. You can search “Front-end highlights” on wechat to read it in the first time, and reply to [Books] to get 200G video materials and 30 PDF books