The year 2022, once thought to be far away, has arrived in a twinkling of an eye. Since I graduated from university, I have been engaged in front-end development industry for five years. I have been proficient in the development of business needs in daily work, but I always feel that there is still a lot of room for improvement. Perhaps IT is the bottleneck that we often face every three or five years.

An excellent front-end engineer can not only efficiently complete page development, but also master and practice a series of front-end engineering technologies, including scaffolding and project script, test system, monitoring system, project specification, project construction and packaging, project deployment and operation and maintenance, etc. Not only can I do projects, but also have enough experience and plan to do projects well, which can be in performance optimization or technical aspects, such as long list optimization, loading performance optimization, improving project maintainability, etc., and technical aspects, such as micro front-end, server rendering, cross-end development, etc.

When you feel confused, what you need to do is to adjust your attitude in time, clear your mind, reflect on and precipitate your past, so that your ability can be further improved.

Number in the fragmentation of time going to and from work to read some public tweets, often feel knowledge does not pass, the basis of the knowledge of the front end of the development as a system, while it now to review your not so busy before the Spring Festival, plan the next write a deep understanding of JavaScript series, this blog is the first article of the series Start with JavaScript prototypes and prototype chains.

Object oriented JavaScript

Those of you who have studied Java know that object-oriented languages have three major features: encapsulation, inheritance and polymorphism. But JavaScript is not strictly an object-oriented programming language; it is a prototype-based language through which inherited features can be implemented.

Here’s an example:

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

Person.prototype.language = 'chinese'

Person.prototype.sayName = function() {
    console.log('My name is ' + this.name)
}

Person.prototype.sayAge = function() {
    console.log('My age is ' + this.age)
}

Person.prototype.getLanguage = function() {
    console.log(this.language)
}

let foo = new Person('foo', 25)
console.log(foo.sayName()) // My name is foo
console.log(foo.sayAge()) // My age is 25
console.log(foo.getLanguage()) // chinese
Copy the code

From this example, we can see that the sayName and sayAge methods are not present in the constructor Person, but foo’s instance object successfully calls them. Why? This is because it inherits both methods from the prototype object. This example leads us to the topic of today’s discussion: what are the internal connections between JavaScript stereotypes, instances, and constructors?

Prototype prototype

Each function has a prototype attribute that points to the prototype of the instance object created by the function, from which the instance objects inherit properties, meaning that the properties and methods of the prototype are shared by all instance objects. So what is a prototype? A prototype can be understood as when an instance object is created, it will have an object associated with it. This object is often referred to as a prototype.

The relationship between the constructor and the stereotype can be expressed as follows:

How does the instance relate to the prototype?

__proto__ properties

Each instance object has a __proto__ private attribute, which points to the constructor’s prototype object, meaning that the instance object is associated with the prototype through the __proto__ attribute. Let’s refine the diagram between instance, constructor, and prototype:

Note that the __proto__ attribute was never included in the ECMAScript language specification, but all modern browsers implement it. The __proto__ attribute has been standardized in the ECMAScript6 language specification to ensure Web browser compatibility, so it will also be supported in the future, but it is no longer recommended, Now, more recommended is the use of Object getPrototypeOf/Reflect getPrototypeOf and Object setPrototypeOf/Reflect setPrototypeOf.

The __proto__ attribute is an accessor attribute inherited from Object.prototype that exposes the internals of an Object [[prototype]]. If an object sets another.__proto__ attribute, the original constructor prototype object will be overridden, meaning that changing the __proto__ attribute of the object will change the prototype chain. The prototype chain will be covered below.

As mentioned above, every instance object has a __proto__ attribute. What does the __proto__ point to for objects created in different ways?

Object literals create objects
let person = {
    name: 'tom',
    age: 22
}
Copy the code

As you can see from the console output, an Object constructed from an Object literal whose __proto__ refers to Object.prototype is also a constructor.

The constructor creates the object
function Person() {}
let p = new Person()
Copy the code

The way to create an object in this form is through the constructor, which in this case is the Person function. As mentioned earlier, an object created from a constructor’s __proto__ refers to the constructor’s prototype object.

Object.create Creates an Object
let person = {
    name: 'tom',
    age: 22
}
const subPerson = Object.create(person);
Copy the code

The __proto__ attribute of the Object subPerson created by Object.create refers to person.

if (typeof Object.create ! == "function") { Object.create = function (proto, propertiesObject) { if (typeof proto ! == 'object' && typeof proto ! == 'function') { throw new TypeError('Object prototype may only be an Object: ' + proto); } else if (proto === null) { throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument."); } if (typeof propertiesObject ! == 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument."); function F() {} F.prototype = proto; return new F(); }; }Copy the code

With this polyfill code, it’s easy to see why the __proto__ attribute of subPerson points to person in the above example.

Since the instance object has a __proto__ attribute pointing to the prototype object and the constructor has a prototype attribute pointing to the prototype object, does the prototype object have any attributes pointing to the instance and constructor? Since constructors can create many instance objects, there are no properties that have a one-to-one relationship to the prototype object, but each instance object inherits properties and methods from the prototype.

constructor

Because a prototype Object can point to a constructor via its constructor property, this property is actually inherited from Object.prototype via the prototype chain. To further refine the diagram of instance objects, constructors, and prototype objects:

Instance objects and stereotypes

From the example at the beginning of this article, we learned that the instance object inherits properties and methods from the prototype object of its constructor. For example, when foo calls getLanguage, it gets the language property of the object and prints it out, but foo doesn’t have the language property set, so it looks up the prototype object associated with it. The foo.proto === Person.prototype object, which happens to have this property on it, and the property value is “Chinese”, so it prints correctly. But what if the constructor prototype of the instance object doesn’t have this property either? It looks up the prototype object of the prototype until it finds the property.

Prototype chain

Since the prototype of the constructor is also an object, by which constructor is it created? And to whom does its __proto__ attribute point? Object literals are created by the original Object constructor. The prototype Object is also created by the constructor. The __proto__ attribute of the prototype naturally points to object. prototype. We further refine the diagram for instance objects, constructors, and prototypes:

Object. Prototype is an Object, so who does its __proto__ attribute point to? Null, that’s right, null.

The chain that extends from foo instance objects to null through the __proto__ attribute is the prototype chain.