Ways to add a prototype to an object:

  • By new (everything in JS can be new out, new out of the object in order to implement inheritance, must have an implicit prototype pointer attribute __proto__)
  • With Object.create
  • Literal prototype chain (same as new)

Here we analyze the prototype chain formed in these two ways:

A new constructor -> creates the prototype chain of the object:

The following constructor example and implementation of new can be better understood by looking at the implementation of the new operator

__proto__ and prototype

function Person(name,age){
 this.name = name;
 this.age= age;
 this.fn=(a)= >{ console.log('methods')}
}
Person.prototype={ 
    fn1:function(){console.log("fn1")}}var p=new Person('andy');// No parentheses, no arguments
p.name//"andy"
p.fn()Function _new(/*constr,params*/){/ *constr,params*/){//... It is more convenient to arg
   let args=[...arguments];
   let constructor=args.shift();
   var newObj={};
   newObj.__proto__=constructor.prototype;
  //let newObj = Object.create(constructor); //issue let result =constructor.apply(newObj ,args); console.log("result",result,"newObj ",newObj ) return typeof result === "object" ? result: newObj } var p = _new(Person,'andy',22); // the first argument is a constructor, and the rest are other arguments (constructor private attributes, methods); Create an object and point its prototype to the constructor's prototype; Call the constructor and point this to the newly created object; Return this object, if the constructor returns an object (it is not recommended that the constructor return a value), otherwise return the newly created object;Copy the code


We only need to focus on this line of code:

 newObj.__proto__=constructor.prototype;

We all know that new is a constructor that returns an object;


So, the object that new is creating, as you can see visually from the code above,


This object has a __proto__ attribute that points to the constructor’s prototype

The conclusion is that only objects have implicit stereotypes, and only functions have explicit stereotypes. The correct conclusion will continue below.

So, we are thinking down: in the next step, ha ha ~


Number.prototype.__proto__===Object.__proto__;  //false
Number.prototype.__proto__===Object.prototype;  //true
Object.prototype.__proto__;   //nullCopy the code

The number’s Prototype object is also an object, so it also has a __proto__ attribute.

@Keep thinking: Number is both a function and an object. So, he has both archetypal properties.

Number.__proto__; ƒ () {[native code]}
Number.__proto__===Function.prototype;  //true

Number.prototype;//Number {0, constructor: ƒ, toFixed: ƒ, }
Copy the code



Look at constructor

Each constructor’s prototype has a Construtor pointing at himself

Number.prototype.constructor===Number  //trueCopy the code

Found a very weird problem:

Object.__proto__.__proto__.__proto__;   //nullCopy the code

What’s going on here? ~ ~



Wrap the prototype chain for object 1

new Number(1).__proto__.__proto__.__proto__===null  //true
(1).__proto__.__proto__.__proto__===null   //truenew Object({a:1}).__proto__.__proto__===null //trueCopy the code


@ Diagram prototype chain

  • Everything in JS is an object, the object will have a __proto__ attribute.
  • Number and Object are constructors, so they both have prototype objects. On this prototype object, there are attributes such as __proto__ and constructor attributes. (See Figure 1 below)
  • The constructor has not only the Prototype object, but also an additional __proto__ attribute. (See chart 2 below)




@ The prototype chain starting from the constructor

  • __proto__ on the Number constructor,__proto__ (not Number. Prototype)

Number.__proto__===Function.prototype; // true
Function.prototype.__proto__===Object.prototype;  // true
Object.prototype.__proto__===null;   // true


Number.__proto__.__proto__.__proto__ === null;  //true
Copy the code

  • __proto__ on the Object constructor,Prototype: __proto__

Object.__proto__;  ƒ () {[native code]}
Object.__proto__ ===Function.prototype; // true
Function.prototype.__proto__===Object.prototype;  // true
Object.prototype.__proto__===null;   // true
Object.__proto__.__proto__.__proto__===null;  // true

Copy the code

  • __proto__ on the Function constructor,Function. Prototype Object __proto__

This chain is special. __proto__ on Function refers to its own prototype object.

Function.__proto__;  ƒ () {[native code]}
Function.__proto__===Function.prototype;   // trueFunction.prototype.__proto__ === Object.prototype; // trueObject.prototype.__proto__ === null; // true
Function.__proto__.__proto__.__proto__===null;  // true
Copy the code


  • Number The prototype chain starting from the __proto__ property on the prototype object

Number.prototype.__proto__===Object.prototype;   // true
Object.prototype.__proto__ ===null;   // true
    Copy the code


  • The __proto__ attribute on the Object constructor, pointing to function. prototype, (proves that Object is the essence of the Function.) (Object has a __proto__ attribute, because only objects have a __proto__ attribute, proving that Object is an Object.) = shows that all constructors have both prototype and __proto__. This further proves that everything in JS is an object. {number 1, string, Boolean (Is the wrapped object)Regular expressions, Function, Number, and Object are all objects}.
  • Object

Prototype the __proto__ on the prototype Object points to Object.prototype



Object.__proto__===Function.prototype;   // true
Function.prototype.__proto__===Object.prototype;   // true
Object.prototype.__proto__ ===null;   // true
Copy the code



Only functions have a prototype, and only objects that are not functions have no prototype.

new Number(1).prototype; //undefinedCopy the code

Everything is an object in JS. All have the implicit prototype __protot__


new Number(1).__proto__; //Number {0, constructor: ƒ, toFixed: ƒ, }
(1).__proto__; //Number {0, constructor: ƒ, toFixed: ƒ, }

Number.__proto__; ƒ () {[native code]}; ƒ () {[native code]}

Array.__proto__; ƒ () {[native code]}; ƒ () {[native code]}
RegExp.__proto__; ƒ () {[native code]}; ƒ () {[native code]}
String.__proto__; ƒ () {[native code]}; ƒ () {[native code]}
Object.__proto__; ƒ () {[native code]}; ƒ () {[native code]}

Symbol.__proto__; ƒ () {[native code]}; ƒ () {[native code]}
Date.__proto__; ƒ () {[native code]}; ƒ () {[native code]}

undefined.__proto__; //VM3065:1 Uncaught TypeError: Cannot read property '__proto__' of undefined
null.__proto__;//VM3065:1 Uncaught TypeError: Cannot read property '__proto__' of undefined
Copy the code

Create a chain of prototypes created by Object.create

Object.create(proto [,propertiesObject]) : Creates a prototype Object with multiple properties.

Parameters:

  • Proto (required) : Prototype object, which can be null to indicate that there is no prototype.
  • Descriptors (Optional) : An object containing one or more attribute descriptors.

PropertiesObject Parameter description

Data attributes

  • Value: the value
  • Writable: Indicates whether the value of an attribute can be modified
  • Different: Indicates whether the system is freely accessible
  • Delete: deletes the attribute
  • Enumerable: Whether you can enumerate for-in
  • Access properties Get () : access set() : set

Example:

function Person(name){
    this.name = name;
  }
  Person.prototype.say = function(){console.log('my name is ' + this.name +',my age is ' + this.age); }var person = new Person('andy');
  var p = Object.create(person,{
    age: {value: 23.writable: true.configurable: true
    },
    sex: {configurable: true.get:function(){return sex + 'and'; },set:function(value){sex = value; }}}); p.sex ='male';
  p.say(); //'my name is andy,my age is 23'
  console.log(p.sex); / / 'man'
  p.sex = 'woman';
  console.log(p.sex);/ / Ms.Copy the code

The @object.create prototype chain

p.__proto__.__proto__.__proto__.__proto__;//nullCopy the code

@object.create prototype chain 2

var a1={}
a1.prototype; //undefined
a2.prototype; //undefined
var a2=Object.create(a1)
a2.__proto__===a1 ;   // true
a1.__proto__===Object.prototype ;   // true
a2.__proto__.__proto__.__proto__===null;   // true


Copy the code




@ note:

A1 has no prototype object prototype; The prototype object a2 points to is A1 itself!

The basic implementation principle of @object. create

The input parameter is a prototype object, and the output parameter is a constructor after new. The prototype of this constructor points to the input parameter Obj.

function create(obj) {
  function F() {}
  F.prototype = obj;
  return new F();
}Copy the code

The internal implementation is done by creating a constructor and then creating an instance that points to the constructor we specified. Finally returns an object. The object of the specified prototype is created.

Iv. Precautions for the use of prototype chain:

  • Do not be too long prototype chain, affect query efficiency!
  • Not only does the prototype object have its own __proto__ attribute on it, but the constructor also has its own __proto__ attribute. Can be interpreted as having two __proto__ on a constructor. But, one on his archetypal object, one on himself.
  • Only functions have prototype, (some objects are functions, but all functions are objects)
  • Everything is an object in JS. All have implicit archetypes __proto__
  • (1), [], {}, true, “ABC”, Object, Function, Array, String all have __proto__, imagine that without this implicit prototype pointer, there is no way to implement inheritance.


Five, question derivation:

The implicit prototype of Object refers to the Function prototype Object. Only this point is a backward anaphora, pointing backwards to Function and then pointing backwards. Then point to null

Object.__proto__.__proto__.__proto__;   //nullCopy the code

Object.__proto__ ===Function.prototype;   //true
//Function.__proto__ === Function.prototype; //trueFunction.prototype.__proto__===Object.prototype; //true
Object.prototype.__proto__===null;   //true
Copy the code



Principle and implementation of Instanceof

Speaking of prototype chain, we have to talk about Instansof, so let’s see how Instansof is implemented first

Instanceof is used to do detection types

Instanceof checks whether an object A is an instanceof another object B:

Check whether the prototype of object B points to an object on the [[Prototype]] chain of object A. Returns true if yes, false if no. There is a special case, however, where object B’s prototype is null (similar to a null-pointer exception).

The function simulates A instanceof B

function instans_of(obj,func){
	var obj = obj.__proto__;// Take the implicit prototype of the object obj
	var func = func.prototype;// Take the display prototype of the constructor
    while(true) {if(obj===null) {return false};
        if(obj===func){return true};// return true if obj is strictly func
       obj=obj.__proto__;//}}Copy the code

Prototype: obj __proto__ is not strong equal to func.prototype, not equal to obj.__proto__.__proto__ until __proto__ is null


@instanceof is valid for all objects in the prototype chain, so multiple constructors may return true for the same instance object

Vii. Summary of type judgment methods

  • typeof

Basic types such as Number, Boolean, Undefined, String, Null, and other reference types and Null return object

  • instanceof

Checks whether an object A is an instance of another object B


  • Object.prototype.toString



Object.prototype.toString.call(' ');//"[object String]"

Object.prototype.toString.call(Symbol);//"[object Function]"

Object.prototype.toString.call(Symbol());//"[object Symbol]"Object.prototype.toString.call([]); //"[object Array]"Object.prototype.toString.call(RegExp()); //"[object RegExp]"Object.prototype.toString.call({}); //"[object Object]"Object.prototype.toString.call(Symbol()); //"[object Function]"Copy the code

Seven, the prototype chain of students

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

function Student(score){
    this.score = score;
}

Student.prototype = new Person('li Ming'.22);
var s = new Student(99);

console.log(s instanceof Student);  //true
console.log(s instanceof Person);  //true
console.log(s instanceof Object);  //true
Copy the code

s.__proto__ === Student.prototype;   // true
Student.prototype; //Person new return object {name: "li Ming ", age: 22}
Student.prototype.__proto__===Person.prototype;   // true
Person.prototype.__proto__===Object.prototype;   // true
Object.prototype;/ / {constructor: ƒ, __defineGetter__ : ƒ, __defineSetter__ : ƒ, hasOwnProperty: ƒ, __lookupGetter__ : ƒ,... }
Object.prototype.__proto__===null; // true

s.__proto__.__proto__.__proto__.__proto__===null; // true
Copy the code

// Implicit archetypes on Object and Function archetypes refer to each other's archetypes. (Pointing to each other)
Object.__proto__===Function.prototype;   // true
Function.prototype.__proto__===Object.prototype;   // true
Copy the code





@ Summary of small examples:

  • Implicit archetypes on Object and Function archetypes point to each other’s archetypes. (Pointing to each other)
  • S has __proto__ and no prototype. Its __proto__ refers to Student’s Prototype object.
  • __proto__ on Student. Prototype points to the prototype object of Person’s prototype.
  • Prototype objects have only __proto__ attributes and constructor attributes
  • __proto__ () {constructor (); proto__ () {constructor (); __proto__ (); Add properties and methods on the prototype object yourself if necessary.
  • Student. Prototype = new Person(‘ li Ming ‘,22); This line of code implements the __proto__ on the Student. Prototype object that points to Person’s prototype. Student has a Prototype object. And both are the object {name: “Li Ming “, age: 22}. Student. Prototype (new Person
  • Student.prototype.name can be taken from an object. The property under this in the Person constructor is for instances of new, not for itself. He doesn’t need it himself.

  • Note also that the constructor on the Student prototype object points to its constructor, Person,PersonThe constructor on the prototype object points to its own Person,

Person.prototype.constructor===Person; // true
Student.prototype.constructor===Person; // trueObject.prototype.constructor===Object; // trueCopy the code

All constructor prototype objects have a constructor that points to the constructor itself. Because he doesn’t have his own constructor.

Constructor whose instance object I am

function F(){};
var f = new F();
f.__proto__.constructor===F; // true
F.__proto__.constructor===Function; // true
F.prototype.constructor===F; // true
Function.__proto__.constructor===Function; // true
Copy the code

Number.prototype.constructor===Number; // true
Number.__proto__.constructor===Function; // true
Object.prototype.constructor===Object; // true

Copy the code

__________________________________________________________________

@ Look at the pictures to deepen the impression

var a=new Number(1);
a.prototype; // undefined
a.__proto__.constructor===Number; // true

Number.__proto__.constructor===Function; // true
Number.prototype.constructor===Number; // trueFunction.prototype.constructor===Function; // true
Function.__proto__.constructor===Function; // true
// all are objects
typeof a.__proto__; //"object"
typeof  Number.prototype; //"object"// Default preference for __proto__ attribute object constructor
a.constructor===Number; // true
Number.constructor===Function; // true//
a.constructor===Function; // false
Copy the code



@ constructor:

  • a.constructor===Number; Or a. __proto__. Constructor = = = Number; Constranctor on the implicit stereotype is used by default.
  • Constranctor under Prototype is not recommended.
  • Except for objects like (1), all other constructors (that is, all other objects) have two constructors.
  • We just need to remember to use constanctor directly.
  • Key: I am the instance object constructed by who.


Nine, literal prototype chain (literal is actually new out, the prototype chain is the same)

__proto__ always points to prototype


__proto__ under prototype always points to Prototype. In addition to null

var o={};
o.__proto__===Object.prototype;
Object.prototype.__proto__===null
({}).__proto__.__proto__===null


var arr=[1]
arr.__proto__===Array.prototype
Array.prototype.__proto__===Object.prototype
Object.prototype.__proto__===null
[1].__proto__.__proto__.__proto__===null
Copy the code



Ten,

  • __proto__ and Prototype are both objects.

  • Only functions have Prototype. Functions also have two __proto__. One on the function itself and one on its prototype object.
  • Only objects have __proto__. Recall the new implementation obj.__proto__=courstranctor.prototype.
  • __proto__ always points to prototype
  • __proto__ under prototype always points to Prototype. In addition to null

  • Everything in JS is an object, the object will have a __proto__ attribute.

  • Only functions have Prototype. (1), “ab”,[],{} and other instances are without prototype. Because they are data objects (instance objects), not functions.
  • Functions also have __proto__, and two of them




— — — — — — — — — — — — — — — — — — — —

@ To be added and improved:

  • isPrototypeOf()Method allows you to check if an object exists on another object’s prototype chain.

  • The __proto__ property, used to read or set the prototype object of the current object
  • Object.setprototypeof () (write operation), Object.getPrototypeof () (read operation)

@__proto__ attribute, multi-angle reference thinking

@ It is essentially an internal property, not a formal external API, and was added to ES6 due to widespread browser support. The standard clearly states that only browsers must deploy this property, not other runtime environments, and that new code is better off assuming this property does not exist. Therefore, for both semantic and compatibility reasons, do not use this property. Instead, use the following object.setPrototypeof () (write operation), Object.getPrototypeof () (read operation), object.create () (build operation)

@__proto__

Back in the object

That is, when a.b is executed, if the current object does not define a b attribute, the parent object is searched through A.__proto__, and so on

The @__proto__ implementation (pasted from the web below) is unverified

Object.defineProperty(Object.prototype, '__proto__', {
    get() {
       let _thisObj = Object (this);
       return Object.getPrototypeOf(_thisObj);
   },
   set(proto) {
       if (this= = =undefined || this= = =null) {
           throw new TypeError(a); }if(! isObject(this)) {
           return undefined;
       }
       if(! isObject(proto)) {return undefined;
       }
       let status = Reflect.setPrototypeOf(this, proto);
       if(! status) {throw new TypeError(a); }}});function isObject(value) {
    return Object(value) === value;
}Copy the code