concept

  1. In JavaScript, functions are allowed to have attributes. All functions have a special attributeprototype, a prototype object called a function; Also in the prototype object, there is a property called constructor that points to the function itself.
  2. After an object (new) is created based on the constructor, each instance object has a private__proto__Property, a prototype object that points to its constructor, used in ES6Object.getPrototypeOf()To access the prototype of the object.
  3. The prototype object has its own prototype object__proto__, layer up until some prototype object is null.
  4. Almost all objects in JavaScript are instances of Object, whose prototype Object is null, at the top of the prototype chain.

Note: If we modify the original stereotype object and assign the stereotype object to an object, we must manually refer back to the original constructor using constructor

Prototype chain

A prototype chain is a chain of __proto__ sequences.

When trying to access an object’s properties, it searches not only on that object, but also the object’s prototype __proto__, and the prototype __proto__ of that object’s prototype __proto__.__proto__, working its way up until it finds an attribute with a matching name or reaches the end of the prototype chain.

Note: How do you tell whether a property is basic or derived from a prototype? The answer:hasOwnProperty

for (let item in obj) { // Lists all enumerable properties on obj and its prototype chain
    if (obj.hasOwnProperty(item)) { ... } // hasOwnProperty is a method in Object.prototype
}
Copy the code

Create an object to construct a prototype chain

Objects created using syntactic structures

var o = {a: 1};
// Prototype chain: o --> Object. Prototype --> null
// Inherit Object. Prototype properties: hasOwnProperty, etc

var a = [1];
Prototype --> array. prototype --> object. prototype --> null
// Inherit array. prototype attributes: forEach, indexof, etc

function f(){}Prototype: f --> Function. Prototype --> Object. Prototype --> null
// Inherit function. prototype attributes: call, bind, etc
Copy the code

Object created using the constructor

In JavaScript, a constructor is just a normal function. When this function is used with the new operator, it can be called a constructor.

function Foo() {
    this.value = 1;
}
Foo.prototype.showValue = function(){ // Public methods are defined on the constructor prototype
    console.log(this.value);
};
var foo = new Foo();// Prototype chain: foo --> foo. Prototype --> Object. Prototype --> null
Copy the code

Note: We can define these immutable methods directly on the Prototype object so that all object instances can share them.

Create the Object created with object.create

The prototype takes the object.create argument to generate a new Object.

var fooProto = { 
    showValue: function(){ console.log(this.value); }};var foo = Object.create(fooProto, {
    value: {
        value: 1.writable: true.enumerable: true.configurable: true}});// Prototype chain: foo --> fooProto --> object. prototype --> null
Copy the code

An object created using the class keyword

ECMAScript6 introduces a new set of keywords to implement class. Developers using class-based languages will be familiar with these constructs, but they are different. JavaScript is still based on prototypes.

These new keywords include class, constructor, static, extends, and super.

class Foo {
  constructor(value) {
    this.value = value;
  }
  showValue(){ console.log(this.value); }}var foo = new Foo(1);
Copy the code

inheritance

We know that the three main characteristics of OOP are inheritance, encapsulation, and polymorphism (overloading, overwriting).

Js is not a strictly object-oriented language, because object-oriented JS is implemented based on prototype chains.

First define the parent class to inherit from:

function Parent(name, height) {
    this.name = name;
    this.height = height;
    this.getName = function(){
        console.log('Name:'.this.name);
    };
}
Parent.prototype.getHeight = function(){
    console.log('Height:'.this.height);
};
Copy the code

Use constructors to implement inheritance

Key: call the constructor of the parent class in the function object, so that it can obtain the methods and attributes of the parent class.

function Child(name, height, age) {
    Parent.apply(this, [name, height]); // Change the Parent's this pointer to run so that the Child instance has the Parent's attributes and methods
    this.age = age;
}
let ch = new Child('a'.170.21); Prototype: ch --> Child. Prototype --> Object. Prototype --> null
Copy the code

Advantages:

  • Subclass instance attributes are not shared
  • Subclass instances can be created to pass arguments to the parent class
  • Multiple inheritance can be implemented by changing this of the parent class with call/apply

Disadvantages:

  • Instances are instances of subclasses, not superclassesch instanceof Parent === false
  • Can only inherit instance properties and methods of the parent class, not methods on the parent class prototype (ch.getHeight()Complains)
  • Function reuse is not possible, because each subclass has a copy of the parent function’s properties and methods, which takes up a lot of memory, and when the parent class’s methods change, the created subclass instance cannot update the method

Inheritance is implemented using prototype chains

function Child(age) {
    this.age = age;
}
let pa = new Parent('a'.170);
Child.prototype = pa; // Key: The prototype of Child is set as an instance of Parent
Child.prototype.constructor = Child; // To avoid breaking the prototype chain, point constructor to itself

Parent.prototype.show = function(){
    console.log('show');
} // All subclass instances can access the new method added by the parent class
let ch = new Child(21); // Prototype chain: ch --> PA --> Parent. Prototype --> Object. Prototype --> null
Copy the code

Advantages:

  • The relation between a subclass and its parent class is a pointing relation. An instance is both an instance of a subclass and an instance of its parent class
  • Any new stereotype method or attribute added by the parent class can be accessed by the child class

Disadvantages:

  • Reference type values on stereotype attributes are shared by all instances, which interact with each other
  • Adding attributes and methods to subtype stereotypes must be done after replacing stereotypes.
  • Cannot pass arguments to the parent type constructor while creating an instance of a subtype

Portfolio model

The parent class is inherited by combining the advantages of both structure inheritance and prototype inheritance. Attributes are inherited with constructs, while archetypal inheritance methods.

function Child(name, height, age) {
    Parent.apply(this, [name, height]);
    this.age = age;
}
Child.prototype = new Parent('a'.170);
let ch = new Child('a'.170.21);
Copy the code

Advantages:

  • A subclass may pass arguments to its parent class
  • An instance is both an instance of a subclass and an instance of a superclass
  • There is no problem with reference attributes of a common parent class between instances
  • An instance can inherit properties and methods from a parent instance, as well as properties and methods from a stereotype

Disadvantages:

  • The constructor of the parent class is called twice, generating two instances where the same properties exist in both the instance and the stereotype

Parasitic combinatorial inheritance

Instead of calling the parent class’s constructor to specify a subclass’s prototype, get the parent class’s prototype object and inherit it.

The difference from composite inheritance is that the parent object is not instantiated.

It combines almost all the advantages of construction, prototype chain and combinatorial inheritance.

function Child(name, height, age) {
    Parent.apply(this, [name, height]);
    this.age = age;
}

(function(){
    let Temp=function(){}; // Create a temporary class
    Temp.prototype=Parent.prototype; // The prototype of a subclass points to an instance of its parent class
    Child.prototype=newTemp(); }) ()let ch = new Child('a'.170.21);
Copy the code

Es6 class inheritance syntax

Grammar is more intuitive and writing is easier.

class Parent {
    constructor (name, height) {this.name = name;
        this.height = height;
    }
    static show() {
        console.log('show');
    }
    getName() {
        return this.name;
    };
    getHeight() {
        return this.height;
    };
}
 
class Child extends Parent {
    constructor (name, height, age) {
        super(name, height);
        this.age = age; }}let ch = new Child('a'.170.21);
Copy the code

Note: When an inherited function is called, this refers to the currently inherited object, not the inherited function’s prototype object.

reference

  1. Inheritance and prototype chains
  2. Getting started with JavaScript Objects
  3. Js prototype chain, 6 kinds of inheritance and its case