JS object oriented, around the prototype and prototype chain knowledge. In this article, you will learn about prototypes, prototype chains, and how to think about these kinds of interview questions. I believe this article will help you to have a good conversation with your interviewer when facing these kinds of questions.

An interview question

function A() {};
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

This is a classic interview question about prototypes and prototype chains. I’m sure some of you can figure it out, so we’re going to start off by talking about prototypes, prototype chains, constructors, new and the love and hate between them. In addition, to give you a better understanding, please come back and have a look at this problem when you get lost

Constructor (function A() {};) And the prototype

When we learn, to understand why the method was created, and to understand what problems people created it to solve, so that we can really understand and apply it

So why prototypes and prototype chains? Let’s start with constructors

function Person(name, age) {
        this.name = name;
        this.age = age;
        this.drinkwater = function() {
            console.log(this.name);
        };
     }
     let person1 = new Person('jack', 18);
     let person2 = new Person('rose', 17);
     person1.drinkwater(); //jack
     person2.drinkwater(); //rose
Copy the code

Above we simply created two new objects using the constructor. As you can see, the constructor is fine. We just need to new and pass in the parameters we want to pass to get the object we want.

So, if he’s so good why do we need a prototype and a prototype chain? Look at the code

console.log(person1.drinkwater == person2.drinkwater);
Copy the code

It has to be false, right. Because the constructor creates drinkwater methods for person1 and person2, respectively, what’s wrong with that? Of course, there is a problem can be big, like everyone every day to use the water dispenser, you feel that the water dispenser a person a he reasonable 🐎?

Isn’t it a huge waste of resources to give person1 and Person2 a water cooler each? So we figured out a way to get these people to stop using their own water fountain and find a water fountain in a common area when they need it. So how do we find it?

To solve this problem, we proposed prototypes and prototype chains.

function Person(name, age) { this.name = name; this.age = age; } / / through the constructor's prototype attribute of the Person to find the Person of the prototype object. The prototype. Drinkwater = function () {the console. The log (enclosing name); } let person1 = new Person('jack', 18); let person2 = new Person('rose', 17); console.log(p1.drinkwater === p2.drinkwater); // trueCopy the code

We found that we shared a water cooler by adding methods to the constructor’s Prototype.

What? Prototype works so well. Don’t worry, I’ll have to talk a little bit more about this constructor in order to get a better sense of what’s left.

A quick word about constructors

A constructor is really just a function, so what’s the difference between it and a normal function? There is only one difference: how it is called.

Any function (yes, any function) that is called through the new operator is a constructor. Functions that are not called with new are normal functions. For example, the Person () defined in the previous example could be called like this:

Person("Tom", 20);
window.drinkwater(); //Tom
Copy the code

Because it is a direct call and does not use the new operator, the result is to give properties and methods to the window object

What happened inside New

Next, I will directly present the internal process of new. If you don’t understand something, don’t worry. Let’s look down first.

This happens when we call the constructor with the new operator:

Create a new object

2. The prototype property inside the new object is assigned to the constructor’s prototype property (*).

3. This inside the constructor is assigned to the new object

4. Execute code inside the constructor (add attributes to the object)

5. The constructor returns the created object

How does sharing water fountains work? The point is that line (*) says that the __proto__ property of the new object constructed by the constructor points to the constructor’s Prototype property.

The Drinkwater is stored in the constructor’s Prototype property. When people want to drink, they go to the constructor’s Prototype Drinkwater using their __proto__ property.

As a result, people share the water cooler (constructed objects are instances, and methods are shared)

Back to the prototype

So with all this guidance, now these concepts need to be memorized

  1. Js is divided into function objects and ordinary objects. Each object has a __proto__ attribute, but only function objects have a Prototype attribute

  2. Object and Function are built-in js functions, similar to Array, RegExp, Date, Boolean, Number, String

So what are __proto__ and prototype

  1. The __proto__ attribute is an object that has two attributes, constructor and __proto__, of which proto refers to the prototype;

  2. The prototype object prototype has a default constructor property that records which constructor the instance is created from;

Now let’s figure out the relationship between the instance (the object constructed by the constructor), the constructor, and the prototype. Without further ado, go directly to the code, or the previous example:

Function Person(name, age) {// constructor this.name = name; this.age = age; } Person. Prototype. Drinkwater = function () {/ / Person for prototype. The prototype to add water dispenser method to the console. The log (enclosing name); } let person1 = new Person('jack', 18); Let person2 = new Person('rose', 17); // Create instance person1.drinkwaterCopy the code

The constructor creates the instance and points its proto property (prototype) to its prototype so that the two instances can share methods. (The ugliness of the picture is acceptable.)

This is what people do when they want to drink water first check if they have a water cooler. Yes? Why don’t you use your own? Check to see if there are public water fountains available in public areas.

The same is true for instance, when you call a method, you see if you have that method first if you’re not looking for it in the prototype.

A lot of people here misunderstand that the prototype of the instance is the constructor’s prototype (***)

Don’t think of it that way. When we create an instance, we just point the instance’s proto property to the prototype for the constructor. We can change the __proto__ property of the instance to something else. We can say that after the constructor creates the instance, the instance has nothing to do with the constructor itself, but its prototype is the prototype of the constructor. If we then rewrite the prototype object as another object, the instance will still be able to call the method in the original Prototype object

This point you can go back to the beginning of the interview question (*), can be more intuitive understanding.

Prototype chain

Now I make two method calls based on the above code:

person1.drinkwater(); //jack
person1.toString();   //[object Object]
Copy the code

Aye??

There is no toString () method in the constructor’s prototype or in the instance itself.

This is because when I try to access an instance’s properties or methods, it first searches the instance itself; When it finds that an instance does not define a corresponding property or method, it searches for the instance’s prototype object instead. If it can’t find any of the prototype objects, it searches for the prototype object of the prototype object, and the trajectory of the search is called the prototype chain.

Take the call to our Drinkwater and toString methods as an example. Their search looks like this:

Back to the interview question

With all that said, let’s go back to the interview question. I believe you can tell the correct output of this question. So what is your output? Now let’s find the prototype chain

function A() {};
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

Two, three, three?

or

One, undefined, two, three?

The answer is number two.

Now let’s start at the beginning.

  • Constructor a. protoType adds an attribute n of 1

  • Constructor A creates an instance of b. The _proto_ of instance b saves a reference to the constructor’s prototype, which in this case contains a n = 1 plus a constructor (not important here). So n of instance B is 1; And since it has no m property, it prints undefined.

Some students will say that, but we also made some changes to the prototype of A. B If I save the reference, it should sense my change ah! Here comes the big part. //* n: 2, m: 3} //* n: 2, m: 3}

While attributes and methods can be added to the prototype at any time and immediately reflected in the instance, rewriting the entire prototype is a different matter. The _proto_ pointer to an instance is automatically assigned by calling the constructor and does not change even if the prototype is changed to a different object. So rewriting the entire stereotype disconnects the original stereotype from the constructor, but the instance still references the original stereotype. (This echoes my *** above)

Here’s a picture that I hope you can understand

From the figure, we can see that A unilaterally cut off the relationship with the old Prototype, while B still keeps the reference of the old prototype. This is what causes the difference in performance between instance B and instance C.

In the face of the interview

What should we do when we meet this kind of problem? Is there a more reasonable way to think about it?

The key to thinking about problems like this is to grasp the prototype chain. As long as we calm down to find the prototype chain, this kind of problem is almost instant solution. And you can try to use this idea to look at other topics on prototypes and prototype chains.

expand

Now that we understand stereotypes and stereotype chains, we can look at some of the more classical inheritance styles (classical inheritance, composite inheritance, parasitic inheritance, prototypical inheritance, parasitic composite inheritance) and the principles of ES6’s class classes. The class class is the basic syntactic sugar structure of ES6. But these are all based on prototypes and prototype chains. It’s easy to understand the JavaScript prototyping paradigm once you really understand prototypes and prototype chains, and these extensions come in handy.

The e Little Red Book of Modern Tutorials and a tutorial I paid for myself. I can’t say it here in case it’s advertising

If there is any error, please correct, I hope this article is helpful to you