The original article was posted on Dreamapplehappy /blog, and if this article is updated, it will be updated on my blog.

The things we most boast about are the things we don’t have

The prototype and inheritance of JavaScript is a problem that every student who learns JavaScript will face, and it is also a required topic for many interviews. But there are often some students who know a little about it, or dabble; This is because many of the articles on archetypes and inheritance are not easy to understand, and the purpose of this article is to help you sort this out once and for all; I hope I can be a good bowler this time.

The first thing we need to know is that JavaScript is a dynamic language, essentially it has no classes; But it also needs a way of inheritance, that is archetypal inheritance; Some properties and methods of JavaScript objects are inherited from other objects.

A lot of you don’t understand JavaScript archetypes and inheritance very well, and one of the big reasons is that people don’t understand it__proto__andprototypeWhat these two properties mean. Let’s take a closer look at these two properties to see where they exist, what they mean, and what they do.

Let’s start with the __proto__ attribute. We need to know that all data types in JavaScript have this attribute except null and undefined. It means: When we access a property of an object that does not have the property itself, we continue to look for the property from the __proto__(p0) property of the object. If __proto__(P1) is present on p0, The response property is then searched on P1 until it is found, or there is no __proto__ attribute. It can be represented by the following two pictures:

The image above shows the value of the property named A found on the prototype chain of OBJ

The image above shows that the value of the attribute name a is not found on the prototype chain of OBj

We take an object__proto__The object to which the property points is called the object’sThe prototype; We can modify an objectThe prototypeTo make this object have some property, or some method.

// Modify a prototype of a value of type Number
const num = 1;
num.__proto__.name = "My name is 1";
console.log(num.name); // My name is 1

// Modify an object's prototype
const obj = {};
obj.__proto__.name = "dreamapple";
console.log(obj.name); // dreamapple
Copy the code

It is important to note that the __proto__ attribute, which is supported by most browsers, is only explicitly defined in the ECMAScript 2015 specification in order to create a standard for this traditional function and ensure compatibility between browsers. Modifying the prototype of an object by using the __proto__ attribute is a very slow and performance-limiting operation. So now if we want to get the prototype of an Object, we recommend object.getPrototypeof or reflect.getPrototypeof, It is recommended to use Object.setPrototypeOf or reflect. setPrototypeOf to set an Object’s prototype.

So far, let’s conclude with the __proto__ attribute:

  • Where does it exist?In addition tonullandundefinedAll other JavaScript objects or primitive types have this property
  • What does it represent? Represents the prototype of an object
  • What does it do? You can get and modify the prototype of an object

With the __proto__ attribute out of the way, we need to take a closer look at the Prototype attribute; The first thing to remember is that this property generally only exists on function objects; Any function that can be used as a constructor contains this attribute. That is, as long as this function can generate a new object by using the new operator, it must have the Prototype property. Because our custom functions can generate an object through the new operator, our custom functions all have the prototype property.

// Function literals
console.log((function(){}).prototype); / / {constructor: ƒ}

// Date constructor
console.log(Date.prototype); // {constructor: ƒ, todate: ƒ, toISOString: ƒ, }

// math.abs is not a constructor and cannot generate a new object with the new operator, so it has no prototype property
console.log(Math.abs.prototype); // undefined
Copy the code

So what does this Prototype property do? The prototype property is an object generated by the function using the new operator, whose prototype (that is, __proto__) points to the function’s Prototype property. A more concise equation that expresses the relationship between the __proto__ and prototype attributes is as follows:

// where F represents a custom function or a built-in function with a prototype attribute
new F().__proto__ === F.prototype // true
Copy the code

We can use this diagram to illustrate the above relationship more graphically:

This equation gives you a better understanding of the relationship between __proto__ and prototype.

Ok, let’s summarize the Prototype property as well:

  • Where does it exist?Custom function, or can passnewThe built-in function that generates an object
  • What does it represent?It means that some function goes throughnewThe prototype of the object generated by the operator
  • What does it do?You can let a function passnewMany objects generated by the operator share some methods and attributes

I’ve covered JavaScript archetypes and inheritance pretty much at this point; The following are some expansions based on the above to give you a better understanding of what we said above.

Once we understand the above, we can make a decision about the following expression:

// Since Object is a Function, Function constructors are all functions
Object.__proto__ === Function.prototype // true

// The __proto__ attribute of a Function defined by a Function literal points to function.prototype
(function(){}).__proto__ === Function.prototype // true

// The __proto__ attribute of an Object defined by an Object literal refers to Object.prototype
({}).__proto__ === Object.prototype // true

// The __proto__ attribute of the Object function prototype points to null
Object.prototype.__proto__ === null // true

Function is also a Function, so Function's __proto__ attribute points to its prototype
Function.__proto__ === Function.prototype // true

Function. Prototype's __proto__ attribute points to Object.prototype
Function.prototype.__proto__ === Object.prototype // true
Copy the code

If you can sort out the above expressions, then you have a good grasp of this part of the knowledge.

There’s one more concept we need to know when it comes to JavaScript archetypes and inheritance; Constructor. What is constructor? Constructor denotes the constructor of an object. All data types in JavaScript except null and undefined have this property; We can verify this with the following code:

null.constructor // Uncaught TypeError: Cannot read property 'constructor' of null ...
undefined.constructor // Uncaught TypeError: Cannot read property 'constructor' of undefined ...

(true).constructor ƒ Boolean() {[native code]}
(1).constructor ƒ Number() {[native code]}
"hello".constructor ƒ String() {[native code]}
Copy the code

We can also use the following diagram to be more specific:

But the above diagram isn’t exactly accurate, because an object’s constructor property doesn’t exactly exist on that object; Instead, it exists on top of the object’s prototype (if multi-level inheritance requires manual modification of the prototype’s constructor property, see the code at the end of this article), which we can use to explain:

const F = function() {};
// When we define a function, the constructor property above the function's prototype property points to itself
F.prototype.constructor === F; // true
Copy the code

The following image illustrates what the above code represents:

There is something else to note about constructor. For primitive types of JavaScript, their constructor property is read-only and cannot be modified. We can verify this with the following code:

(1).constructor = "something";
console.log((1).constructor); ƒ Number() {[native code]}
Copy the code

Of course, if you really want to change the constructor property of these primitive types, you can do so as follows:

Number.prototype.constructor = "number constructor";
(1).constructor = 1;
console.log((1).constructor); // Output number constructor
Copy the code

Of course the way we are not recommend you to use in the development of the real, if you want to learn more about the content of the constructor, can look at the Object. The prototype. The constructor.

Next, I’ll use some code to briefly review what I’ve learned today:

function Animal(name) {
  this.name = name;
}

Animal.prototype.setName = function(name) {
  this.name = name;
};
Animal.prototype.getName = function(name) {
  return this.name;
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);

// Since the above statement changes our prototype reference, we need to redefine the constructor property of Dog's Prototype property
Reflect.defineProperty(Dog.prototype, "constructor", {
  value: Dog,
  enumerable: false.// Not enumerable
  writable: true
});

const animal = new Animal("potato");
console.log(animal.__proto__ === Animal.prototype); // true
console.log(animal.constructor === Animal); // true
console.log(animal.name); // potato

const dog = new Dog("potato"."labrador");
console.log(dog.name); // potato
console.log(dog.breed); // labrador
console.log(dog.__proto__ === Dog.prototype); // true
console.log(dog.constructor === Dog); // true
Copy the code

That’s pretty much the end of this article, but there’s a lot more to learn about JavaScript prototyping and inheritance, and a lot more to learn; But that’s the end of the article.

I’ll write a little bit more about JavaScript archetypes and inheritance, if you’re interested; You can also click here to leave a comment.