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
class
The 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
public
Is 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 method
this
, 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 component
props
Property, which can be initialized by a constructor, and is defined by the parent - One for each component
state
Property defined by the parent - There must be one for each component
render
The 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
TypeScript
Only 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 class
implements
An interface, then the contract defined in that interface must be implemented - Use multiple interfaces
.
separated implements
与extends
Coexisting
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
Person
Class (constructor)- through
Person
Instantiated 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