To understand prototype in JS, you must first understand the following concepts
1. Everything in JS is an object
2. Everything in JS is derived from Object, that is, the end point of the prototype chain of all things points to Object.prototype
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", // "__lookupSetter__"] console.log(Object.getOwnPropertyNames(Object.prototype));
3. The subtle relationship between constructors and instances (objects) in JS
The constructors define prototypes to agree on the specifications of their instances, and then construct instances through new. Their function is to produce objects.
The constructor (method) itself is an instance of the method (Function), so it can also be found for its __proto__(protochain)
Object / function F() {} This is the constructor, one is provided by the JS native API, and the other is customized
new Object() / new F() is an instance
The examples can only be viewed "only" to find out what prototype it is made based on.
The prototype that "cannot" redefines the instance and then deludes itself to create an instance of the instance.
Practice to produce true knowledge, and only by observing/thinking yourself can you truly understand:
// Let’s first look at what the constructor is// function Empty() {} function Empty() {} console.log(Function.prototype, Function.__proto__); // Object {} function Empty() {} console.log(Object.prototype, Object.__proto__); function F() {} // F {} function Empty() {} console.log(F.prototype, F.__proto__);You may be dizzy, let's break it down.
prototype
The format of the prototype output is: Constructor name prototype
First, let’s take a look at what Object.prototype outputs?
Object {} -> The previous Object is the name of the constructor, and the next one represents the prototype. Here is a {}, that is, an instance of an Object object (empty object)
Then F {} we understand what it means. F is the name of the constructor, and the prototype is also an empty object
// Let’s take a look at the example constructed by the constructor var o = new Object(); // var o = {}; // undefined Object {} console.log(o.prototype, o.__proto__); function F() {} var i = new F(); // undefined F {} console.log(i.prototype, i.__proto__);Let's go a little deeper and define the prototype of F to see what will happen?
function F() {} F.prototype.a = function() {}; var i = new F(); // undefined F {a: function} console.log(i.prototype, i.__proto__);In this way, we can clearly see that i is constructed from F, the prototype is {a: function}, which means that a method a has been added to the original empty object prototype.
Let's change the situation, what will happen if the prototype that completely covers F?
function F() {} F.prototype = { a: function() {} }; var i = new F(); // undefined Object {a: function} console.log(i.prototype, i.__proto__);Hey~ Why does it indicate here that i is constructed from Object? No!
Because we completely overwrite F's prototype, in fact, we specify the prototype as an object {a: function}, but this will cause the original constructor information to be lost and become the constructor specified by the object {a: function}.
So what is the constructor of the object {a: function}?
Because the object {a: function} is actually relative to
var o = {a: function() {}} // new ObjectThen the constructor of o is of course an Object
Let's correct this error
function F() {} F.prototype = { a: function() {} } // Re-specify the correct constructor F.prototype.constructor = F; var i = new F(); // undefined F {a: function, constructor: function} console.log(i.prototype, i.__proto__);Now you can get the correct prototype information again~
Prototype chain
Then let’s take a look at what prototype chain is?
Simply put, it is the same as the inheritance relationship (chain) in OOP. Look up layer by layer until the final Object.prototype
The most important thing is to figure out what things in JS are (instances) objects. This is simple, everything in JS is objects!
Then we need to figure out that any object has a prototype!
Then let's prove it:
Object // This is a function, the function is an instance object of Function, so it is the Object.__proto__ == Function.prototype // Then the prototype of the Object, true // This is an ordinary object, so the instance of Object belongs to Function.prototype.__proto__ == Object.prototype // true // This is already the top level of the prototype chain, so the final point is null Object.prototype.__proto__ == null // true Function // This is also a function, yes! Function.__proto__ == Function.prototype // true function A() {} // This is a custom function, and it is still a function after all, that's right! A.__proto__ == Function.prototype // Any function is an instance of Function, so is the prototype of A? var a = new A() a.__proto__ == A.prototype // Instance a is constructed by the A constructor, so a prototype of a is defined by the prototype attribute of A.prototype.__proto__ == Object.prototype // Example of ordinary objects are ObjectsPrototype and __proto__
Each object contains a __proto__ pointing to the "prototype" of the object.
A similar thing is that each function contains a prototype. What is this prototype object for?
Let's look at the following code, using the constructor to create an object (the above is to create an object in the form of a literal form).
function Foo(){};var foo = new Foo();console.log(foo.__proto__);Just imagine, what will the __proto__ of this foo object point to?
An object containing the constructor attribute? It doesn't matter if you don't understand it very much. Print out the prototype attribute of the function Foo and compare it to you to know.
function Foo(){};var foo = new Foo();console.log(foo.__proto__);console.log(Foo.prototype);console.log(foo.__proto__ === Foo.prototype);It turns out that the __proto__ of the object foo that comes out of new only points to the prototype of the function Foo.
foo.__proto__ --> Foo.prototype
What's the point of designing JS like this? Recalling what was mentioned above, in the world of JS, objects are not created based on classes (molds), but are derived from prototypes (another object).
When we perform new operations to create a new object, we will not go deep into the specific implementation of new operations, but we are sure of one thing - that is, we point to a prototype object for the new object __proto__.
Just this code
function Foo(){};var foo = new Foo();Who is foo.__proto__ pointing to? Why can't you point to the function Foo itself? Although the function is also an object, I will talk about it in detail if you have the chance. But it is certainly not appropriate to point to Foo.__proto__Foo, because Foo is a function with a lot of logical code. As an object, it has no meaning to inherit logical processing. What it wants to inherit is the attribute of the "prototype object".
Therefore, each function will automatically generate a prototype object, and the __proto__ of the object new from this function points to the prototype of this function.
foo.__proto__ --> Foo.prototype
Summarize
After saying so much, I still haven't explained it completely, so it's better to be in the previous picture. I have referenced pictures from other netizens, but I always feel that I didn’t explain clearly, so I drew a picture myself. If I think mine is good, please like it! (I have tried my best to draw it).
Let’s take this picture and remember the following facts:
1. There is a _proto_ attribute in each object.
There is no concept of a class (mold) in the JS world. Objects are derived from another object (proto), so there will be a _proto_ attribute in each object pointing to its prototype object. (Refer to the object obj defined in literal form in the upper left corner. It opens up a space to store the object's own properties in memory, and generates a _proto_ pointing to its prototype - the top-level prototype object.)
2. Each function has a prototype property.
Why is "constructor" called a constructor? Because it wants to construct an object. So according to the first fact above, who does the _proto_ attribute of the constructed new object point to? You can't point to the constructor itself. Although it is also an object, you don't want the new object to inherit the properties and methods of the function. Therefore, each constructor will have a prototype attribute, pointing to an object as the prototype of the new object constructed by this constructor.
3. Functions are also objects.
Each function has some common properties and methods, such as apply()/call(), etc. But how do these common methods be inherited? How are functions created? Just imagine, everything is an object, including functions, and is an object constructed through a constructor. Then, according to the second fact above, each function will also have a prototype pointing to its constructor. The function of this constructor is Function, and all functions in JS are constructed from Function. The general properties and methods of functions are stored on the prototype object Function.prototype.