Hello, brave friends, Hello, everyone, I am your mouth strong king xiaowu, healthy body, brain is not sick.

I have a wealth of hair loss techniques that can make you a veteran.

A look will be a waste is my main purpose, food to scratch my feet is my characteristics, humble with a trace of strong, stupid people have silly fortune is the biggest comfort to me.

Welcome to the big talk prototype chain of Xiaowu’s essay series.

preface

Mention it headache, always wandering between half-understanding, this is the author of the prototype chain feeling; And then one day you realize how it came to be, and whoops, that’s all there is to the prototype chain.

This article is the actual application of linked list in JavaScript, if you want to recall the linked list, its portal is as follows: Small five algorithm series – linked list, you see the official according to their own needs.

This article with the author of ignorance, if there is an error, welcome comments correction.

What is a prototype chain

Prototype chain, its essence but a linked list just, do not believe you see 👇

🐳 __proto__ is the next pointer to the list, and the list tail pointer points to null

Prototype chain, and constantly looking for the prototype of the constructor (prototypeprototypeprototype) process, not letter you see 👇

class Person {};
let person = new Person();
Copy the code

🐳 __proto__ – > constructor. The prototype

👺 prototype chains are essentially linked lists, and __proto__ is the next pointer to the prototype of its constructor

The search of prototype chain is the search of linked list, such as Instanceof;

The addition of a prototype chain is the addition of a linked list, such as new;

The operation of the linked list is to fiddle with the pointer, the prototype chain is the same, know how to fiddle with the pointer, the prototype chain will pass;

🐢 There is a rumor that all things are objects; As shown below, the end of the list is always Object.prototype, no matter how variable it is

We can think of Object.prototype as the origin of everything, code 001

Obj’s __proto__ points to the prototype 001 of its constructor Object

🚶 We continue along the prototype chain to the red box, using STR -> string. prototype -> object. prototype -> null as an example, as shown below

The STR in this case is both the base type and the instance type. Instanceof? , first sell in suspense, later the article will see.

let str1 = 'apple';
str1 instanceof Object // false

let str2 = new String('apple');
str2 instanceof Object // true
Copy the code

After the example, let’s talk about the constructor, which is the class; Different classes do their job and work together to improve our JavaScript world;

These classes are created directly, and their __proto__ refers to function. prototype, which we also call 002

__proto__ === function. prototype and function. __proto__ === function. prototype __proto__ refers to the prototype of its constructor, while all classes are constructed by Function, including Object and Function

“New” an object

👀 what will happen to “new”? Let’s take a look

Start by creating a Person class

function Person (name) {
  this.name = name;
  this.action = function () {
    console.log('Play 🏓️ table tennis'); }}let person = new Person(Yellow Knife Little Five);
Copy the code

The process of new is similar to inserting an element at the head of a linked list, and __proto__ points to the prototype of its constructor.

function new (P, ... args) {
  letobj = {}; obj.__proto__ = P.prototype; P.call(obj, ... args);// Change this to point to P
  return obj;
}

let person = new(Person, Yellow Knife Little Five); // same as above
Copy the code

Object.create()

Official definition: The object.create () method creates a new Object, using an existing Object to provide the __proto__ of the newly created Object

So straightforward description, just follow suit

Object.Create = function (obj) {
  let newObj = {};
  newObj.__proto__ = obj;
  return newObj;
}
Copy the code

As a sighted citizen, object.create () creates an Object whose __proto__ refers to its input parameter obj, not object.prototype.

createObj -> obj -> Object.prototype -> null
Copy the code

Talk about inheritance

Don’t be alarmed by the list of strange names, they are just a breakdown of the big moves, follow them step by step as you explore the evolution of inheritance.

Let’s build a Teacher class and a Student class to inherit from it.

function Teacher (name) {
  this.name = name;
  this.info = {};
  this.action = function () {
    console.log('Do the exercises'); }};Copy the code

🐳 Prototype chain inheritance

The idea of prototype chain inheritance is to rewrite the Student prototype to make it equal to the Teacher instance to achieve the effect of inheritance, the code is as follows:

function Student () {};
Student.prototype = new Teacher();
Copy the code

At this time encountered a very embarrassing problem, Teacher class is to receive parameters, how should I pass it ❓ can not pass parameters, this is a crime 1 also.

Teacher has an info object representing basic information, I create two instances of student, as follows, what happens if I change the age in their info respectively?

student1.info.age = 12;
student2.info.age = 13;

console.log(student1.info.age, student2.info.age); / / 13 13
Copy the code

Will point to the same address, the value is changed, this sin 2 also.

🐳 constructor inheritance

The idea is to inherit the parent class by calling the parent class’s constructor from the subclass’s constructor

function Student (. args) {
  Teacher.call(this. args); }Copy the code

We append a method eat to Teacher’s prototype

Teacher.prototype.eat = function () {
  console.log(`The ${this.name} eat apple`);
}
Copy the code

Called in the student instance

const student = new Student(Small five ' ');
student.eat(); // student.eat is not a function
Copy the code

It is a sin not to be able to access properties and methods in a superclass stereotype

🐳 combinatorial inheritance

To put it bluntly, the above two are unusable. Let’s sew them up and they become combinatorial inheritance.

function Student (. args) {
  Teacher.call(this. args); } Student.prototype =new Teacher();
Student.prototype.constructor = Student; // assign constructor to Teacher otherwise
Copy the code

Seemingly perfect, can achieve the effect of inheritance; The parent constructor is actually called twice, causing unnecessary wear and tear

🐳 Prototype inheritance

A shallow copy, which is essentially an object.create (), will be written the same way

function create (o) {
  let P = function () {};
  P.prototype = o;
  return new P();
}
Copy the code

The shortcomings are inherited from the prototype chain and will not be repeated

🐳 Parasitic inheritance

Parasitism is just copying, and then extending, adding study methods on top of the stereotype inheritance.

function createStudent (o) {
  let clone = create(o);
  clone.study = function () {};
  return clone;
}
Copy the code

🐳 Parasitic combinatorial inheritance

Now let’s welcome our ultimate boss, who, remember the combinatorial inheritance problem, calls the superclass constructor twice; Then we will not directly point to the Teacher instance this time, but copy a Teacher prototype to perfectly solve the above problems.

function Student (. args) {
  Teacher.call(this. args); } Student.prototype =Object.create(Teacher.prototype);
Student.prototype.constructor = Student;
Copy the code

Handwritten instanceof

STR instanceof Object -> false because on the instanceof implementation, all non-object types return false; If the object type, it is the search of the linked list; Is it so easy? Let’s do it together.

const instanceof = (L, P) = > {
  if (typeofL ! = ='object') return false;

  let current = L.__proto__;
  while (current) {
    if (current === P.prototype) return true;
    current = current.__proto__;
  }
  return false;
}

instanceof('str'.String) // false
instanceof({}, Object) // true
Copy the code

A profound

Prototype chain interview questions I encountered in 2020

👺 No. 1

Function.prototype.a = () = > {
  console.log(1);
}
Object.prototype.b = () = > {
  console.log(2);
}
function A() {};
const a = new A();

a.a();
a.b();
A.a();
A.b();
Copy the code

Resolution:

The answer:

a.a(); // Error
a.b(); / / 2
A.a(); / / 1
A.b(); / / 2
Copy the code

👺 No. 2

var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
  n: 2.m: 3
}
var c = new A();

console.log(b.n);
console.log(b.m);

console.log(c.n);
console.log(c.m);
Copy the code

Resolution:

The answer:

console.log(b.n); / / 1
console.log(b.m); // undefined
console.log(c.n); / / 2
console.log(c.m); / / 3
Copy the code

👺 No. 3

function A() {};
A.prototype.n = 0;
A.prototype.add = function () {
  this.n += 1;
}

a = new A();
b = new A();
a.add();
console.log(b.n);
Copy the code

Resolution:

When add() is executed, n = 0 is found along the prototype chain, this.n += 1, at which point, A gets the attribute n, whose value is 1, and b does the same

The answer:

console.log(b.n); / / 1
Copy the code

See 🔗 for links

The birth of the world

There are eight inheritance schemes commonly used in JavaScript