The past and present of JavaScript’s prototype and prototype chain (1)

You don’t have to be frightened by the name of this feeling. I’m not going to say the history of the prototype. This article just wants to help you understand why the prototype and the prototype chain is a unique language, and other languages (or the programming words I’ve learned) have not seen this concept. It was also the most puzzling puzzle when I switched from C to JavaScript.

1. First from JavaScript to create objects

As we all know, JavaScript is an object oriented language, but there is no concept of class (except the current ES6 standard). Personally feel that ES6 is a new standard encapsulated on ES5, and its essence is ES5. Therefore, mastering ES5 is the essence. There is no concept of class, but there must be the concept of object, and the object of JS is different from other object oriented languages (such as C++). Each object is based on a reference type (such as Array/Date/Function and so on, which belongs to the reference type, with a specific reference to the fifth chapter of the JavaScript advanced programming (Third Edition)) or a custom type.

The most common way to create objects before was (by creating a Object instance):

Var animal = new Object ();

Animal.name =’WangWang’;

Animal.type =’dog’;

Animal.say = function () {

Console.log (‘I am a ‘+ this.type);

}

After that, a method of creating an object literal is presented.

Var Animal= {

Name:’WangWang’,

Type:’dog’,

Say: function () {

Console.log (‘I am a ‘+ this.type);

}

}

First of all, it is clear that an object must contain attributes and methods: name and type are definitely attributes, and say is definitely a method. Second, attributes have corresponding properties inside the browser, which are used by the internal JS engine.

1.1. Talk about the properties in the JS object (Property)

In accordance with the ES5 standard, attributes are a name that we know in the impression, a value, similar to the form of a key pair, in fact, there is a large article inside the browser.

Attributes are divided into data attributes (‘Data Property’) and accessor properties (Accessor Property). The name and type that have just been defined are data attributes, and the basis for distinguishing data attributes and accessor data is that the accessor property has a [[Get]] and [[Set]] method and it does not contain a [[value]] feature (Attribute).

The data attribute contains 4 characteristics: [[configurable]], [[Enumerable]], [[Writable]] and [[Value]].

The accessor property contains 4 properties: [[Configurable]], [[Enumerable]], [[Get]], [[Set]].

Although these features are internal use of browsers, ES5 still provides the interface for us to call:

Object.defineProperty (obj, prop, descriptor);

Object.defineProperties (obj, props);

Object.getOwnPropertyDescriptor (obj, prop);

Object.getOwnPropertyDescriptors (obj);

Take an example (in the Chrome console):

> Object.getOwnPropertyDescriptor (Person, " name")

> Object {value: " WangWang" writable: true, enumerable: true, configurable: true}

More details of these 4 API (such as compatibility) can be used as reference: MDN

2. Create the advance of the JS object

Although the Object constructor or object literal can be used to create a single object, it is obvious that there is a clear flaw: this method of mixing object creation and object instantiation directly leads to code cannot be reused and a heap of repeated code will be generated, so to solve this problem A new way of creating objects — factory mode has been created. This form begins to approach the instantiation of classes and objects in the C++ language, and is closer to the actual code development.

2.1. Factory model

A very image of the name, as soon as we hear the name, we know that there is a factory at that time. As long as we provide the raw materials, we can use the mold of the factory to help us create the objects we want (that is, the instantiation process).

Because ES5 is unable to create classes, you can only use functions to encapsulate the details of creating objects with specific interfaces. For example:

Function createAnimal (name, type) {

Var o = new Object ();

O.name = name;

O.type = type;

O.say = function () {

Console.log (‘I am a ‘+ this.type);

}

Return o;

}

Var dog = createAnimal (‘WangWang’,’dog’);

Although this approach solves the problem of object instantiation code repetition, it does not solve the problem of object recognition (that is, the object created in this way can’t know its type, for example, the object created by the second previous methods can know that the type of its object is Person). So there is another way to create objects.

2.2, constructor pattern

Constructors are a basic concept in the C++ language, whose function is to initialize calls after instantiating an object, and to perform some replication operations, which can be considered as an initialization function. Similarly, the constructor used by JS is different from C++ in nature, but its essence is the same. JS provides some native constructors such as Object/Array/String, etc., and can also create custom ones. For example:

Function Animal (name, type) {

This.name = name;

This.type = type;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

}

}

Var dog = new Animal (‘WangWang’,’dog’);

This constructor has the following three features:

There is no explicit creation of objects

Assign attributes and methods directly to the this object

No return statement

In performing new operations, you will experience the following 4 steps:

Create an object

Assign the scope of the constructor to the new object (so the this pointer points to the new object).

Execute the code in the constructor

Return a new object

At this time dog is an instance of Animal. According to the tradition of the C++ language, each instance must have an attribute called constructor, and JS is the same, and the constructor attribute of the instance in JS points to the Animal constructor.

The first three methods create the same object, so take one and compare it with factory mode.

It can be seen that the constructor method is indeed more than one attribute, and why these attributes are concentrated in __proto__ is exactly what we should mention later.

So we can identify the type of the object through the constructor attribute (for example, the Animal type in this example), that is, use instanceof to verify.

Of course, using the constructor is not perfect, the main problem with using the constructor is that each method is created in each instance, that is, when we create the Animal object, the method inside is actually an instance of the Function object, that is, the same as:

This.say = new Function (console.log (‘I am a ‘+ this.type);

This leads to the creation of multiple instances of multiple function objects, which obviously increases memory consumption, and in order to solve this problem, we introduce the prototype mode.

3, prototype model

In Figure 1, we have found that each object, whatever the method is created, has a __proto__ attribute, which is the key to the connection of the prototype chain. In the last section, we have 4 steps to perform the operation of the new, of which second steps are based on the code. It is an assignment operation, that is, dog.__proto__ = Animal.prototype, which can be seen through console printing:

The way to create prototype patterns is to adopt such a form:

Function Animal () {}

Animal.prototype.name =’WangWang’;

Animal.prototype.type =’dog’;

Animal.prototype.say = function () {

Console.log (‘I am a ‘+ this.type);

};

Var dog = new Animal ();

The difference between prototype mode and constructor mode can be seen in the following diagram:

Constructor pattern:

Prototype mode:

From the above two pictures, we can see the advantages and disadvantages of the prototype, and how to improve it. Can the integration of the two make full use of the advantages of the two? If you think so, that means you are right. This is the 3.2 subsection.

In addition to the prototype assignment operation, we prefer to use object literal or new keyword to manipulate the prototype. But the use of object literal or new key words has a very important knowledge point: whether using object literal or new keyword, it is to create a new object to replace the original prototype object.

Is it abstract? A picture to tell you the truth:

Code:

Function Animal () {}

Animal.prototype = {{

Name:’WangWang’,

Type:’dog’,

Say: function () {

Console.log (‘I am a ‘+ this.type);

}

}

Var dog = new Animal ();

Or:

Function Species () {

This.name =’WangWang’;

This.type =’dog’;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

};

}

Function Animal () {}

Animal.prototype = new Species ();

Var dog = new Animal ();

The prototype pattern diagrams of the two ones are illustrated.

So precisely because of this overridden effect, when you use this method, you must pay attention to whether the prototype object is still the original prototype object.

Both of the two have the advantages. How do they use the combination? What does the prototype chain have to do with the prototype?

Look at the next chapter: the past and present of the prototype and prototype chain of JavaScript (two).

Leave a Reply

Your email address will not be published. Required fields are marked *