preface

Start from a didi interview question, is a very basic prototype, prototype chain question, but also need to know the relationship between the prototype and the prototype chain, in order to better answer, after all, maybe your clear thinking is also very important oh. Without further ado, let’s take a look at the title:

Object.prototype.a = "jing1";
Function.prototype.a = "jing2";
function Preson() {};
var p = new Preson();
console.log(p.a);
console.log(p.constructor);
console.log(p.__proto__.__proto__.constructor);
Copy the code

I think you have a good prototype, you should be able to say the answer, please keep your answer in mind. But don’t be too basic to read the following article, I just use it as a primer to clarify the knowledge of this area.

Ok, let’s get started. First put the map:

An object,

1. Create objects

Objects can be defined in one of two forms

  • Word grammar:
var jingObj = {
  key: value;
  //
}
Copy the code
  • Structural form:
var jingObj = new Object(a); jingObj.key = value;Copy the code

There is not much difference between the two forms, except that the literal syntax of creating an object can define multiple objects, and the binary constructor type needs to be added one by one (which is rarely used).

2. The content of the object

An object is a container that encapsulates properties and methods.

3. Property access

var jingObj = {
  a: 2
}
jingObj.a = 2; / / 2
Copy the code

We create a jingObj object and access the properties through jingobj.a, but this access actually involves the following steps:

  • JingObj. A actually implements the [[Get]] operation on jingObj. The default [[Get]] operation on an object first goes back to the object to see if there is an attribute with the same name, and returns the value of that attribute if there is.
  • If it does not find an attribute with the same name, the [[Get]] algorithm defines a lookup in the stereotype chain and returns the value of the attribute when it is in the stereotype chain (described below)
  • [[Get]] returns undefined if the end (which is also described below) is not found

Second, the prototype

1, the introduction

In javascript, objects have a special [[Prototype]] reference to other objects, and almost all objects are created with a non-null value assigned to the [[Prototype]] property. (But it can be null)

Note: ([[prototype]] has the same meaning as __proto__. Both are internal properties of the object, and their values refer to the object’s prototype. The former represents the stereotype properties of an object in books and specifications, while the latter points to the stereotype in the browser implementation.

Okay, so we know that the object has this property, so what does it do? The same code as before:

var jingObj = {
  a: 2
}
jingObj.a = 2; / / 2
Copy the code

As we said above, when it cannot find this property on the object call [[Get]], it will look for it on the prototype chain, such as when we create a new object associated with jingObj:

var jingObj = {
  a: 2
}
var newObj = Object.create(jingObj);
console.log(newObj.a);/ / 2
Copy the code

We create an Object with object.create () and associate the Object’s [[Prototype]] with the specified Object.

However, if newobj. a is not found on jingObj and [[Prototype]] is not empty, it will continue to look until it finds a matching property name, or if it is not found, undefined.

var jingObj = {
 
}
var newObj = Object.create(jingObj);
console.log(newObj.a);//undefined
Copy the code

2. End of prototype chain

Where exactly the end of the prototype chain is not explained, let’s see. In fact, all normal [[Prototype]] chains eventually point to object.prototype. This object. prototype Object contains many of the functions commonly found in javascript.

3, some methods on Object

For example: -.create(): This method takes an object as an argument and returns an instance object based on that object. This instance fully inherits the properties of the prototype object.

// Prototype object
var Jing = {
  name: function() {
    console.log('jingda'); }};// Instance object
var Hao = Object.create(Jing);
Object.getPrototypeOf(Hao) === Jing;
Hao.name();
console.log(Jing.name === Hao.name);
Copy the code
  • .toString() :
  • .valueOf() :
  • .hasOwnProperty() :

The hasOwnProperty method of an object instance returns a Boolean value that determines whether a property is defined on the object itself or on the stereotype chain

Date.hasOwnProperty('length') // true

Date.hasOwnProperty('toString') // false
Copy the code

Length is an attribute of Date (how many arguments the constructor Date can take), but toString is not.

Personal words, used for deep copying. There is one caveat: the hasOwnProperty method is the only JavaScript method that works with object properties without traversing the prototype chain.

  • .isPrototypeOf() :

The isPrototypeOf method of the instance object to determine whether the object is the prototype of the parameter object.

  • .getPrototypeOf() :

The object. getPrototypeOf method returns the prototype of the parameter Object. This is the standard way to get a prototype object using:

var F = function () {};
var f = new F();
Object.getPrototypeOf(f) === F.prototype // true
Copy the code

Third, “love triangle” relationship

About a “love triangle” relationship, I want you to know, like this picture describes:As you can see from the figure above, an instance object can be created by the constructor using new, and the instance object has a __proto__ attribute that refers to the constructor’s prototype object. A constructor is related to a prototype object, so there is a property on the constructor that points to the prototype object, and there is a property on the prototype object that points to the constructor.

Let’s look at this with a code example:

function Person() {}var p = new Person();
console.log(Person.prototype === p.__proto__);//true
console.log(Person.prototype.constructor === Person);//true

console.log(p.constructor === Person);//true
Copy the code

I think you’ll notice that in the love triangle diagram above, I didn’t specify the instantiation to the constructor, but in the code, I used p.structor === Person because instance P itself has no constructor property, This property is available on Person.prototype, and by default points to the Person constructor. So the p.structor here is actually delegating to person.prototype.

The constructor property of person. prototype is simply the default property of the Person function when it is specified

When we try to define a person. prototype, it continues to look up the prototype chain, like this:

function Person() {
}
Person.prototype = {}
var p = new Person();

console.log(p.constructor === Person);//false
console.log(p.constructor === Object);//true
Copy the code

In this case, p.structor points to Object instead of Person, because we’ve created a new Object and replaced the function’s default. Prototype Object reference.

Four, look at the prototype chain (not easy)

When I first saw this picture, um… Touching. But understanding it is the purpose of this picture. Think back to the interview question at the beginning of this article. Did you answer the following? jing1 [Function: Preson] [Function: Object]

All right, if you have a good foundation, just review it. If you don’t know, just follow me through the picture.

  • This diagram is divided into three parts, (left) is the instance of new (middle) is the constructor, including the custom Function, Function, Object (right) prototype Object, which is the constructor of the middle.
  • We start with three centers, namely

1. Focus on the constructor Foo()

2, centered on the constructor function Object()

3, centered on the constructor function function (

Function Foo();

1. With a new Foo() operation, you create an instance object (like f1) that has a __proto__ attribute pointing to the constructor’s prototype object foo.prototype ().

2, Foo. The prototype and the constructor is Foo prototype. The constructor = = = Foo ();

3, Foo().proto === function.prototype

2, centered on the constructor function Object()

1. With a new Object() operation, you can create an instance Object(like o1), which is similar to the f1 Object instance above

Object.prototype.proto === null;

3, Object. Proto === function.prototype;

3, centered on the constructor function function (

Function. Proto === function.prototype

Function. Prototype__proto__ === object.prototype

Go back to the question at the beginning of the passage

Object.prototype.a = "jing1";
Function.prototype.a = "jing2";
function Preson() {};
var p = new Preson();
console.log(p.a);//jing1
console.log(p.constructor);//[Function: Preson]
console.log(p.__proto__.__proto__.constructor);//[Function: Object]
Copy the code
  • P.a because p has no property of a, so it will look up the prototype chain, first of all, p. roto
console.log(p.__proto__)//Preson {}
Copy the code

So our person. prototype is Preson {}, and you can see that there’s no a property in it, so let’s keep looking,

console.log(p.__proto__.__proto__)//{ a: 'jing1' }
Copy the code

Ok, so here we are, person.prototype. __proto__ is our object.prototype with our property a on it, so print its value

  • P.constructor defaults to our constructor Person, so the output is [Function: Preson].
  • P.p roto. Proto. Constructor, this words, through the prototype chain diagram above can also be clearly know is [Function: Object]

So much for prototypes and prototype chains, let’s look at some of the other things that are involved. (New instanceOf implementation principle, etc.)

5. Implementation principle of new

We know that when we create an instance object through the constructor, we need to use new, so how do we implement the new, and what happens in between?

Calling a function with new, or sending a constructor call, automatically does the following:

  • 1. Create (or construct) an entirely new object.
  • 2. Attach the Object to the constructor’s prototype chain (use object.create () here);
  • 3. This new object is bound to the function call this (consider changing the execution of this apply, etc.);
  • If the function returns no other object, then the function call in the new expression will automatically return the new object, otherwise it will return the returned object.

Ok, let’s look at the code implementation:

const myNew = function (func, ... args) {
	if (typeoffunc ! = ='function') {
		return new TypeError('this is not a function');
	}
	// Create an empty object specifying func.prototype
	const obj = Object.create(func.prototype);
	// Bind this and execute the inner constructor code to add properties to the new object
	const result = func.apply(obj, args);
	// If the constructor returns a non-empty object, return that object; Otherwise, the newly created object is returned.
	return result && result instanceof Object ? result : obj;
};
Copy the code

This is a code that implements new, let’s test it, because it says there are two different cases when the result is returned, so let’s discuss it separately:

  • No other objects are returned:
// Test the simple constructor
function Person(name, age) {
 	this.name = name;
 	this.age = age;
 }

// Write new by yourself
console.log('myNew');
const jing = myNew(Person, 'jing'.22);
console.log(jing.name,jing.age)//jing 22

/ / the original new
console.log('new');
const hao = new Person( 'jing'.22);
console.log(hao.name,hao.age)//jing 22
Copy the code
  • Other objects are returned:
// To test that the constructor returns a reference datatype
function Person(name, age) {
	this.name = name;
	this.age = age;
	return {	
    name:'hao'.age:23}}// Write new by yourself
console.log('myNew');
const jing = myNew(Person, 'jing'.22);
console.log(jing.name,jing.age)//hao 23

/ / the original new
console.log('new');
const hao = new Person( 'jing'.22);
console.log(hao.name,hao.age)//hao 23
Copy the code

When returning a reference type, the last attribute or method used on the instance is the returned reference type. (This is also the reference to this, as I mentioned in the previous article.)

6. InstanceOf operator

The instanceof operator returns a Boolean value indicating whether the object is an instanceof a constructor. As we used in the implementation of new, the constructor returns an Object: Result Instanceof Object

Let’s take a look at how it works, first to understand how it works and how it works:

To the left of the instanceof operator is the instance object and to the right is the constructor. It checks to see if the right constructor’s prototype is on the left constructor’s prototype chain.


const instanceofFunc = function (left,right) {
  if (typeofleft ! = ='object' || left === null) return false;
  // let proto = Object.getPrototypeOf(left);
  let proto = left.__proto__;
  while(true) {
    if(proto === null) return false;
    if(proto === right.prototype) return true;
    // proto = Object.getPrototypeOf(proto)
    proto = proto.__proto__
  }
}
// Define the constructor
function C(){}
function D(){}
var o = new C();
console.log(instanceofFunc(o,C))//true
console.log(instanceofFunc(o,D))//false
Copy the code

There are two methods: get the prototype Object, where the object.getPrototypeof method returns the prototype of the parameter Object. This is the standard way to get a prototype object, as discussed earlier.

conclusion

Well, that’s all for today. The knowledge of prototypes and prototype chains is relatively basic, but also to be honest, really common interview questions, whether it is to ask knowledge points, or to see questions. I hope everyone can make sense of it.

However, personal writing may be a little unsystematic, or not very clear, you are welcome to comment and feedback, you can also go to the “dirty books” – prototypes section to read oh.

👇 👇 👇

I am Jing University, a junior student. I am preparing for the internship interview.

This time should be mainly to straighten out some knowledge points, welcome to study together. Wx: lj18379991972 💕 💕 💕

Your likes are the biggest support for me 🤞

References: MDN object prototype

Javascript tutorial – Prototypes

[[prototype]]