First let’s look at ordinary objects and function objects

Let’s look at normal objects and function objects in javascript before we look at prototypes,

As shown in figure 1

  • Common objects:
    • Most common object: it has the _ _ proto_ attribute. Note: normal objects do not have the prototype attribute! If you call it must return undefined
    • Prototype objects: We’ll continue below!

What are common objects in javascript?

// Common objects
function Test() {}var obj1 = new Test();
var obj2 = new Object(a);var obj3 = {};


console.log(typeof obj1);    //Object
console.log(typeof obj2);    //Object
console.log(typeof obj3);    //Object
Copy the code
  • Function object:

    • Anything created with Function() is a Function object. For example: custom functions, event function system Object, Array, Date, String, RegEx are all function objects

      _ _ proto_ () == all of the above are instance objects of Function, so only instance objects can have the _ _ proto_ _ attributeCopy the code

Function (prototype); Function (prototype); Function (prototype);

In javascript, where are function objects?

// Function object

function F1(){}var F2 = function(){}var F3 = function(a,b){}window.onload=function () {
    var div1=document.getElementById('div1');
    div1.onclick=function () {
        alert(1);
    }
    console.log(typeof div1.onclick);   //function  
}

 
console.log(typeof F1);  	  //function  
console.log(typeof F2);  	  //function  
console.log(typeof F3);       //function  

console.log(typeof Object);   //function  
console.log(typeof Array);    //function  
console.log(typeof String);   //function  
console.log(typeof Date);     //function  
console.log(typeof RegEx);    //function  
console.log(typeof Function); //function  
Copy the code

Function objects are instance objects of Function

Just like Array is created by Function.

ƒ () {[native code]} Array is an instance of Function.

ƒ () {[native code]}

_ _ proto_ === Function. Prototype is true! Returns true

Thus, the following judgment conditions are derived:

Array._ _proto_ _  == Function.prototype     //true

String._ _proto_ _ == Function.prototype     //true

RegExp._ _proto_ _== Function.prototype     //true

Date._ _proto_ _  == Function.prototype     //true
Copy the code
ƒ () {[native code]}

Native code means that it comes with the program, which is binary compiled and cannot be displayed. Native code is native code, and here we simply explain it.

The above content as learning prototype before the foreshadowing understanding!! Let’s break down the details of Figure 1 slowly!


Two questions arise

Problem 1 performance

If an object is created in the heap area of memory, a space is created to hold the object, if each object has the same method in it

The problem is that public methods or properties are stored in memory for n copies. , a lot of memory overhead!

As shown in figure 2

Each object generates the same **say()** method, which would take up a lot of memory if every object had the same method in common!

The code for the image above is as follows

function Person(name,age){
    this.name=name;
    this,age=age;
    this.say=function () {
        console('Output result'); }}var obj1=new Person();
var obj2=new Person();
var obj3=new Person();
var obj4=new Person();
var obj5=new Person();
Copy the code

Problem 2 Property methods cannot be shared!

Sometimes we want a method that can be used by multiple object types in common!

For example, define an array private method that cannot be accessed by another array object

Code examples:

var arr=[5.5.10];
// sum method of arr array object
arr.sum=function () {
    var result=0;
    for(var i=0; i<this.length; i++){ result+=this[i];
    }
    return result;
}

console.log(arr.sum());  // Result: 20

var arr2=[10.10.10];
console.log(arr2.sum()); Uncaught TypeError: arr2.sum is not a function
Copy the code

The sum() method does not exist in arr2. It is a method that is private to arR.

So sometimes we want a method that can be used by multiple objects of the same type in common!

The first problem is that the performance optimization is insufficient, and the second problem is that private methods cannot be called by objects of the same type, so the solution to the above problem is to use: prototype [improve performance] is commonly referred to as: prototype pattern

Now let’s talk about what the prototype is!


What is the prototype object!

According to Figure 1, function objects have a prototype property that points to a prototype object. We can derive the following concepts:

Every function created has a prototype property, which is a pointer to an object.

Prototype object, A.K.A. Constructor, contains a constructor property that points to the current prototype object’s constructor.

The diagram below:

All instances of a particular type will share the properties and methods you define in a prototype object.

The advantage of a prototype object is that it contains properties and methods that can be shared by all instance objects.

The syntactic foundations of prototype objects

For properties and methods of a particular type to be shared by all instances, define them under the prototype object!

To use the ==prototype keyword, write it below the constructor:

// The syntax is as followsConstructor name. Prototype. property = value; Constructor name. Prototype. method =function(){.. Code.. }Copy the code

So with the: constructor name. Prototype you can define properties and methods in your prototype object

Case code:

function createPerson(name,age) {
    this.name=name;
    this,age=age;
}

createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}

var a=new createPerson('Joe'.'33');
var b=new createPerson('bill'.'55');
var c=new createPerson('Wang Wu'.'66');

a.say();
b.say();
c.say();
Copy the code

I have drawn a diagram for easy understanding. The flow chart analysis of the above code is as follows:

The special Function of the prototype

Function. Prototype is the exception. Why is it an exception? It should get a prototype object here, but it’s a function object,

As a function object, it has no prototype property. You can see this in Figure 1!

ƒ () {[native code]} please ƒ () {[native code]}

The diagram below:

Prototype knowledge point

To save memory, we put the object’s methods inside the prototype. Why is that?

Overwrite the common methods or properties of an object so that only one copy of the common methods or properties exists in memory

When we instantiate an object with new, all the properties and methods in the constructor are automatically copied in memory and used to assign values to the object. No matter how many times we instantiate, the properties and methods in the prototype are only generated once, so it saves memory.

Priority of common definition versus stereotype definition

The following code:

function createPerson(name,age) {
            this.name=name;
            this,age=age;
        }

createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}

var a=new createPerson('Joe'.'33');
var b=new createPerson('bill'.'55');
var c=new createPerson('Wang Wu'.'66');

a.say();
b.say();
c.say();

// The normal definition takes precedence over the prototype
c.say=function(){
    console.log('output ok');
}
        
c.say();

Copy the code

So the general definition above takes precedence over the prototype definition! , but this does not override the stereotype, just call normally defined methods first

As shown in figure:


The _ _ proto_ _ in the prototype

To recap, when instantiating new, the system creates an empty object in memory, like var p = {}, copying properties and methods from the constructor into the empty object.

The important thing is that every instantiated object has a _ _ proto_ attribute, which is automatically generated, and the _ _ proto_ attribute points to the protoobject of the class.

The relationship between constructor, instantiated object, and prototype object

Let’s start with a code example

function createPerson(name,age) {
    this.name=name;
    this,age=age;
}

createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}

var obj=new createPerson('Joe'.'33');

console.log(obj.__proto__);              // Instantiate obj's __proto__ property to get the prototype object
console.log(createPerson.prototype);     // The constructor's prototype property can also get the prototype object
console.log(obj.__proto__.constructor);  // The constructor in the prototype object gets the constructor

Copy the code
Basic diagram analysis of constructors, instantiated objects, and prototype objects

Of course you can also verify the result by instantiating the object’s _ _ proto_ property and comparing it with the constructor’s Prototype property, which we can print to verify

console.log(instantiate object._ _proto_ _ === constructor. Prototype);//true
Copy the code

Summary of the differences between definitions in examples and definitions in prototypes:

Let’s start with a code example:

function Test(){}// Define attributes
Test.prototype.name = "Zhang";  
Test.prototype.age =  33;
// Define the method
Test.prototype.getAge = function(){  
    return this.age;  
}  
  
var t1 = new Test();  
var t2 = new Test();
var t3 = new Test();  
t3.name = "Bill";  

console.log(t1.name); // Joe is from the prototype
console.log(t2.name); // Joe is from the prototype
console.log(t3.name); // Li Si comes from examples

// Print an example to see the result below
console.log(t1);
console.log(t2);
console.log(t3);

Copy the code

The diagram above explains why properties and methods defined in the prototype are common, but properties and methods defined separately in the instance are independent.

So we also infer that defining properties and methods in the instance overrides or implements calls to properties and methods defined in the instance and then looks for them in the prototype if not! This is actually the prototype chain we’ll talk about later!

Detailed understanding of _ _ proto_ _ and prototype

1. All reference types, such as arrays and objects, have a _ _ proto_ _ attribute (also called == implicit prototype ==, which refers to its own prototype object)

Again, all object references have the _ _ proto_ attribute! Remember!

In the following tests, we can see that each of them has a _ _ proto_ attribute in the reference object that they assign

The code is as follows:

function createPerson(name,age) {
     this.name=name;
     this,age=age;
}
createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}
var obj=new createPerson('test'.'33');

// Object reference prints
console.log(obj);


var arr=[1.2.3];
// Print array references
console.log(arr);

var arr2=new Array(2.2.2);
// Print array references
console.log(arr2);


Copy the code

**2. Again, note that for all reference types, the _ _ proto_ _ attribute refers to the reference’s own prototype object and the constructor’s prototype attribute is the reference’s prototype object **

So the _ _ proto_ attribute and the constructor’s Prototype attribute are equal to each other in their respective reference types! This can also be shown in the figure above!

The _ _ proto_ attribute and the constructor’s Prototype attribute are compared as follows:

/ / in case 1
function createPerson(name,age) {
    this.name=name;
    this,age=age;
}
createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}

var obj=new createPerson('Joe'.'33');

console.log(obj.__proto__);   		   // Prints the prototype object referenced by the obj object
console.log(createPerson.prototype);   // Prints out the prototype object for the createPerson constructor
console.log(obj.__proto__===createPerson.prototype);  // They are equal and refer to the same prototype object

/ / case 2
var arr=new Array(2.2.2);
console.log(arr.__proto__);
console.log(Array.prototype);
console.log(arr.__proto__ === Array.prototype);
Copy the code

3. All constructors or normal functions have a prototype property (this is also called an explicit prototype, which also points to its prototype object).

Case code:

// A normal function
function Test() {}// Prints the prototype property of a normal function
console.log(Test.prototype);


// constructor
function createPerson(name,age) {
     this.name=name;
     this,age=age;
}
createPerson.prototype.say=function () {
    console.log('My name is.'+this.name);
}

console.log(createPerson.prototype);

Copy the code

The diagram is as follows:

_ _proto _ _ and prototype

==prototype== is an attribute that every function has. It is a pointer to a prototype object that only normal functions or constructors have.

The ==_ proto_ == property is a property supported by mainstream browsers on every reference object except the NULL object that can point to the current reference object: the prototype object is actually the property used to connect the reference object to the prototype

Proto_ proto_ (prototype); proto_ proto_ (prototype);

ƒ () {[native code]} when you call the attribute (_ proto_ _) with a function, you get the following ƒ () {[native code]}

Batch add properties and methods to the prototype

If ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {if ==prototype== {

/ / grammarConstructor. Prototype ={attribute name: value, method name:function(){
        // Method body... What is this in this case depends on who called this function when it was executed}, method name:function(){
       // Method body... What is this in this case depends on who called this function when it was executed}}Copy the code

Case code:

 createPerson.prototype={
     aaa:123.// prototype has other properties inside the object
     showName:function(){
         // What is this depending on who calls the function when it is executed
         console.log("My name is :"+this.name);
     },
     showAge:function(){
         // What is this depending on who calls the function when it is executed
         console.log("My age is :"+this.age); }}function createPerson(name,age) {
    this.name=name;
    this.age=age;
}
var obj= new createPerson('Joe'.'33');
console.log(obj);
obj.showName();
obj.showAge();
console.log(obj.aaa);
Copy the code

The above prototype code diagram

Prototype Considerations

== Pay attention to ==

If you customize a constructor and use {} to batch define properties and methods in prototype, you will change the constructor’s direction in the prototype.

Constructor () {constructor () {constructor () {constructor ()

The test code is as follows

function createPerson(name,age) {
    this.name=name;
    this,age=age;
}

/ * createPerson. Prototype. Say = function () {the console. The log (+ this. 'my name is' name); } * /

createPerson.prototype={
    say:function () {
        console.log('My name is.'+this.name); }}var obj=new createPerson('Joe'.'33');
console.log(obj.__proto__);
Copy the code

In console output you will see the value _ _proto _ _. The constructor property is gone!

console.log(createPerson.prototype.constructor);   ƒ Object() {[native code]}
Copy the code
Prototype basic summary
  1. Keep a copy of the same method in memory
  2. The stereotype definition takes lower priority than the normal definition
  3. Properties and methods that are common throughout the project can be loaded onto the prototype
Core principles of prototype chain

First of all, it should be pointed out that the implementation of inheritance in JS mainly relies on the prototype chain to achieve! That’s why we need to learn how prototype chains work!

Prototype chain core concept

The prototype chain: When you’re trying to call or get a property or method from an instance of an object, if the object doesn’t have the property or method itself meaning that the constructor doesn’t define the property or method you want, The prototype property or method ==(the ‘prototype’ property of its constructor is found in the prototype Object) is returned if it has one, if it doesn’t have one, and if it has one, the top-level Object is returned. Return undefined if still not found! = =

Prototype chain flow chart ==

When the Test constructor has a getName method, there is no need to look for getName in the constructor’s prototype. Instead, look for the getName method in the constructor prototype; If the getName method does not exist in the constructor’s prototype, look for it in the top-level object’s prototype.

The above test case code is as follows:

function Test(name){
    this.name=name;
    this.getName=function(){
        return this.name+"I'm in the constructor."; 
    }
}
Test.prototype.getName=function(){
    return this.name+"I'm in the prototype object.";
}
Object.prototype.getName=function(){
    return this.name+"I'm in the top-level object.";
}
var t1=new Test('little red');

console.log(t1.getName());
Copy the code

Prototype chain case code 2 is as follows:

Array.prototype.aaa=123;    // Define this custom property under the prototype object
var arr=new Array(1.2.3);
console.log(arr.aaa);
console.log(Array.prototype);

var arr2=['chongqing'.'Shanghai'.'Beijing'];
console.log(arr2.aaa);
Copy the code

The diagram below:

== Summary ==: both ARR and ARR2 can find the aaa attribute, and this attribute is a property of the array prototype object, which is common

You can call this property as long as it’s an array, and the same goes for methods,

So when you create lots and lots of objects of the same type, every object that you create, if it has some common method in it, it takes up a lot of resources,

To do this, you just need to assign values to properties in the constructor and write methods in the Prototype property. Properties can also be written in the prototype.

This way every object reference can use a method or attribute from the Prototype attribute and saves a lot of resources

That’s why we use prototypes!


Schematic summary of overall structure of prototype chain

When you try to call or want a property or method in an object instance, If the Object does not have the property or method, the constructor will use the prototype property to look for the property or method. If the Object does not have the property or method, the constructor will return the property or method. = =

But because the prototype property in the constructor is itself an Object, it also has a _ _ proto_ attribute, so you can go up and get _ _ proto_ _, and get the top-level Object

The diagram below:

Conclusion:

When obj calls test(), JS finds that Fn doesn’t have the method, so it goes to Fn. Prototype. When it does, JS calls Test () in Object.prototype.

This is the prototype chain search, and the layer by layer of links is the prototype chain.

Obj can call methods in Object.prototype because of the prototype chain mechanism!

In addition, when working with prototypes, it is generally recommended to write the methods that need to be extended in the constructor. Prototype property,

And don’t write in the constructor. Prototype. _ _ proto _ _, because here is the Object on top of the Object and definition to the properties and methods All JS object can be called, in this definition more can affect the overall performance, the definition is not recommended to here!