Hello everyone, I am Lin Yiyi, today this article is about JS inheritance and simulation implementation of new, I will try to make the article easy to understand, let’s start reading 😁

001 inheritance

Inheritance means that a subclass inherits the methods of its parent class. Inheritance in JS is implemented based on prototypes and prototype chains. For prototype and prototype chain | you have to understand unfamiliar look at interview JS prototype and prototype chain

  • The purpose of inheritance: To give instances of subclasses the same attributes and public methods as their parent classes.

Think 1: What properties and methods does instance C1 have

function Parent(){
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')}function Child(){
    this.name = 'one'
    var name = '二二'
}

Child.prototype.getChildName = function() {
    console.log('Child')}var c1 = new Child
dir(c1)
Copy the code

Instance C1 has name=” lin1 “, and getChildName on the prototype chain (ignoring property methods on Object here). For there is doubt can look at the interview | you have to know the JS prototype and prototype chain. How can C1 obtain properties and methods from Parent?

Simplest prototype inheritance

The prototype of a subclass equals an instance of its parent class. The reason is that subclasses can obtain methods and attributes of their parent class through the look-up mechanism of the prototype chain.

// You can do it in one sentence
Child.prototype = new Parent
Copy the code

Prototype private and public properties of the parent class become public methods of the subclass. Archetypal inheritance refers to the process of finding rather than copying. It is important to note that the inherited parent class instance is the heap memory address is unique, when the value of a heap memory attribute changes, the subclass instance inherits the changed attribute.

  • Drawback: Stereotype inheritance defines the private and common attributes of the parent class as the common attributes of the subclass. If you want the private attributes of the parent class to be the private attributes of the subclass, stereotype inheritance cannot be implemented.

The call to inherit

Before we use call inheritance to privatize private properties, we need to understand how the constructor creates private properties. The constructor can only create private properties by referring to this, so we can use call to change the reference to this in the parent class

function Child(){
    Parent.call(this)
    this.name = 'one'
    var name = '二二'
}
Copy the code

This in Parent is written to the subclass and private attributes can be created when the subclass is instantiated.

  • Defect: Call inheritance can only inherit private attributes of the parent class, not common attributes of the parent class. Call inheritance is equivalent to making a copy of the parent class’s private properties.

Combined Inheritance 1(Call inheritance + subclass prototype chain __proto__ to)

As mentioned above, call inheritance only allows subclasses to inherit private attributes from their parent class, so we can just get the stereotype that the parent class’s common attributes are assigned to the subclass. The Child. The prototype. __proto__ = Parent. The prototype

function Parent(){
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')}function Child(){
    this.name = 'one'
    var name = '二二'
    Parent.call(this)
}

Child.prototype.__proto__ = Parent.prototype

Child.prototype.getChildName = function() {
    console.log('Child')}var c1 = new Child()
dir(c1)
Copy the code

  • Drawback: __proto__ is not available in all browsers, not in version one of IE

Combined inheritance 2(Call inheritance + object.create ()) is recommended

  • Object.create(obj) creates an empty Object whose prototype __proto__ points to obj. In other words, use object.create () to make a copy of the Object’s properties. So this method can also be used as a shallow copy.
let obj = {
    name = 'Lin Yiyi'
}
let a  = Object.create(obj)
console.log(a.__proto__)
Copy the code

  • The function’s prototype property is also an Object, and you can also use object.create () to copy the common properties and methods of the parent class’s prototype. This sentence is equivalent toChild.prototype = Object.create(Parent.prototype)
function Parent() {
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')}function Child() {
    this.name = 'one'
    Parent.call(this)
}

Child.prototype = Object.create(Parent.prototype)

// Subclass constructor is overridden and can be added again
Child.prototype.constructor = Child

Child.prototype.getChildName = function() {
    console.log('Child')}Copy the code

The extend of the class

The class implementation in ES6 is actually based on the prototype and prototype chain in JS.

class Parent{
    constructor(){
        this.name = 'parent'
    }

// equivalent to parent.prototype.getName = function(){... }
    getParentName() {
        console.log(this.name)
    }
}

class Child extend Parent{
    constructor(){
        super(a)this.age = 18
    }
    getChildName() {
        console.log(this.name)
    }
}
Copy the code

conclusion

  • Prototype inheritance is the simplest implementation of JS inheritance, but it cannot distinguish between private and common attributes
  • In composite inheritance, use call inheritance + change subclassesprotoPointing inheritance is the most appropriate approach. The disadvantage is that IE does not support it__proto__
  • Composite inheritance uses call inheritance and Object.create() to make a shallow copy of a method on a parent class prototype.

002 new constructor

The new constructor performs the equivalent of normal function execution.

function Person() {
    this.name = 'Lin Yiyi'
}
new Person()
Copy the code

What happens in the new Person() procedure

  • New creates a heap of memory for the constructor which is the instance object (empty object)
  • Point the prototype chain that creates the empty object to the prototype of the constructor.
  • Execute the constructor, pointing this to the heap memory address (instance object).
  • Returns the created instance object

Note that using return in constructors makes no sense. Returning a primitive type does not block the return of an instance, but returning an object/function overwrites the returned instance because it overwrites the memory address of the instance. More details please see the interview | JS prototype and prototype chain

(Ali) Interview question, implement a _new(), get the expected result

function Dog(name) {
    this.name = name
}

Dog.prototype.bark = function() {
    console.log('wang wang')
}

Dog.prototype.sayName = function() {
    console.log('my name is ' + this.name)
}

function _new() {
    // code
}

let sanmao = _new(Dog, 'three hairs')
sanmao.bark();  // => 'wang wang'
sanmao.sayName(); // => 'my name is'
console.log(sanmao instanceof Dog)  // true
Copy the code

Analyze: Analyze this problem is actually the process of implementing new. The process that occurred in the new constructor above can be implemented as follows

function _new(ctor, ... params) {
    // Create a heap memory address that inherits the common properties on the prototype
    let obj = {}
    obj.__proto__ = ctor.prototype

    // Make sure this points to the heap memory address, and use call to point the constructor's private property to the obj instance for private property inheritance
    letres = ctor.call(obj, ... params)// Return the created instance. If the constructor itself returns an object, it overwrites the instance
    if(res ! = =null && typeof res === 'object') return res
    return obj
}
Copy the code

The execution result is correct. The above simulation implemented new using call+ prototype inheritance

Question: Can arrow functions be new?

Before we answer this question, let’s review the characteristics of the arrow function

  • Arrow functions do not have this, which comes from the context, specifically from the function that wraps the arrow function. Without the wrapping function, this would come from the window
  • The Call /apply methods also have no effect on arrow functions.
  • The arrow function does not have the argument set arguments
  • Arrow functions cannot be constructors because arrow functions have no prototype, so using the new keyword will not work

The end of the

More articles in the interview series

Vue high frequency principle interview + detailed answers

| call the interview, apply, bind the simulation implementation and classic interview questions

Interview | JS closure classic usage scenarios and including closures will brush

Interview | JS, you have to understand this point

The interview | JS event loop event loop classic interview questions with answers

.

Github collection of articles

Thank you for reading so far, if this article can help you or inspire you welcome star I am Lin Yiyi, see you next time.