Home > Article > Web Front-end > Understanding JavaScript prototypes
Javascript prototypes always cause some confusion. Whether it is experienced experts or the author himself, he often shows some limited understanding of this concept. I think this confusion has already arisen when we first come into contact with prototypes. Yes, they are often related to new and constructor, especially the prototype properties of functions. In fact, a prototype is a very simple concept. To understand it better, we should first remember the principle of forgetting what we have learned about constructor prototypes.
What is a prototype?
A prototype is an object through which other objects can implement property inheritance.
Can any object become a prototype?
is
Which objects have prototypes
All objects have a prototype by default, because the prototype itself is also an object, so each prototype itself has a prototype (with one exception, the default object prototype is The top of the prototype chain. More about the prototype chain will be introduced later)
Okay, let’s circle back again, what is an object?
In JavaScript, an object is a collection of any unordered key-value pairs. If it is not a primary data type (undefined, null, boolean, number, or string), then it is an object
You said that every object has a prototype, but when I write it as ({}).prototype I get got a null, are you right?
Forget everything you have learned about prototype properties, it may be the source of your confusion about prototypes. The true prototype of an object is held by the [[Prototype]] property inside the object. ECMA introduced the standard object prototype accessor Object.getPrototype(object), so far only Firefox and Chrome have implemented this accessor. In addition to IE, other browsers support the non-standard accessor __proto__. If neither of these works, we need to find its prototype attribute from the object's constructor. The following code shows the method of getting the object prototype
var a = {};
//Firefox 3.6 and Chrome 5
Object.getPrototypeOf(a); //[object Object]
//Firefox 3.6, Chrome 5 and Safari 4
a.__proto__; //[object Object]
//all browsers
a.constructor.prototype; //[object Object]
ok, everything is going well, but false is obviously a The main data type, but false.__proto__ returned a value
When you try to get the prototype of a main data type, it is forced to be converted into an object
//(works in IE too, but only by accident )
false .__proto__ === Boolean( false ).__proto__; //true
I want to use prototypes in inheritance, so how should I do it?
It doesn’t make much sense to use a prototype just for an instance. This is the same as adding properties directly to this instance. If we have created an instance object, we want to inherit the functionality of an existing object, such as Speaking of Array, we can do it like below (in browsers that support __proto__)
//unusual case and does not work in IE
var a = {};
a.__proto__ = Array.prototype;
a.length ; //0
————————————————————————————————————–
Translator’s Note: In the above example , first create an object a, and then use the prototype of a to inherit the function of the existing object Array
—————————————————— ——————————–
The real charm of prototypes is when multiple instances share a common prototype. Once the properties of a prototype object (note: that is, the object referenced by the prototype of an object) are defined, they can be inherited by multiple instances that reference it (note: that is, the prototypes of these instance objects point to this prototype object) , the significance of this operation in terms of performance and maintenance is self-evident
Is this also the reason for the existence of the constructor?
Yes. Constructors provide a convenient cross-browser mechanism that allows a common prototype to be provided for instances when they are created
Before you can provide an example, I need to know what exactly is the constructor.prototype property?
First of all, JavaScript does not distinguish between constructors and other functions, so each function has a prototype attribute. Conversely, if it were not a function, there would be no such property. Please look at the code below
//function will never be a constructor but it has a prototype property anyway
Math.max.prototype; //[object Object]
//function intended to be a constructor has a prototype too
var A = function (name) {
this .name = name;
}
A.prototype; //[object Object]
//Math is not a function so no prototype property
Math.prototype; //null
Now we can make a definition: the prototype property of function A is an object. When this function is used as a constructor When creating an instance, the prototype attribute of the function will be assigned as a prototype to all object instances (note: the prototypes of all instances refer to the prototype attributes of the function)
—————————————— ——————————————————————-
Translator’s Note: The following code explains all this in more detail
//Create a function b
var b = function( ){ var one; }
//Create an object instance c using b
var c = new b();
//View the constructors of b and c
b.constructor; // function Function() { [native code ]}
b.constructor==Function.constructor; //true
c.constructor; //The constructor of instance c is b function(){ var one; }
c.constructor==b //true
// b is a function, check the prototype of b as follows
b.constructor.prototype // function (){}
b.__proto__ //function (){}
//b is a function, because javascript is not in the constructor constructor Distinguish between function and function, so function, like constructor,
//has a prototype attribute, which is different from the prototype of the function (b.__proto__ or b.construtor.prototype)
b.prototype //[object Object] Prototype attribute of function b
b.prototype==b.constructor.prototype //fasle
b.prototype==b.__proto__ //false
b.__proto__==b.constructor.prototype //true
//c is an object instance created by b. View the prototype of c as follows
c.constructor.prototype //[object Object] This is the prototype of the object
c.__proto__ //[object Object] This is the prototype of the object
c.constructor.prototype==b.constructor.prototype; //false Compare the prototype of c and the prototype of b
c.constructor.prototype==b.prototype; //True Compare the prototype properties of c and b
//Add an attribute max
b.prototype.max = 3
//Instance c also has an attribute max
c.max //3
In the above example, the prototype and object instance c The prototype properties of function b are the same. If you change the prototype properties of b, the prototype of object instance c
will also change
—————————————————————— ————————————-
It is crucial for us to understand that a function’s prototype property has nothing to do with the actual prototype
//(example fails in IE)
var A = function (name) {
this .name = name;
}
A.prototype == A.__proto__; //false
A.__proto__ == Function.prototype; // true - A's prototype is set to its constructor's prototype property
Give me an example
You may have used JavaScript like this hundreds of times, and now when you see such code again, you may have a different understanding.
//Constructor. this is returned as new object and its internal [[prototype]] property will be set to the constructor's default prototype property
var Circle = function (radius) {
this .radius = radius;
//next line is implicit, added for illustration only
//this.__proto__ = Circle.prototype;
}
//augment Circle's default prototype property thereby augmenting the prototype of each generated instance
Circle. prototype.area = function () {
use using using use ‐ ‐ through use using using using ’ ’ ’ s ’ through prototype. area ’ through through using ’ ’s ’ through using ‐ ‐ return Math.PI* this .radius* this .radius;
} //create two instances of a circle and make each leverage the common prototype
var a = new Circle(3), b = new Circle(4);
a.area().toFixed(2); //28.27
b.area().toFixed(2); //50.27
Great. If I change the prototype of a constructor, does that mean that instances of that constructor that already exist will get the latest version of the constructor?
Not necessarily. If a prototype property is modified, then such changes will occur. Because a.__proto__ is a reference to A.prototype after a is actually created.
var A = function (name) {
this .name = name;
}
var a = new A( 'alpha' );
a.name; //'alpha'
A.prototype.x = 23;
a.x; //23
——————————————————————————————————
Translator’s Note: This is the same as the above example Same as in, the prototype (a.__proto__) of instance object a is a reference to the prototype attribute (A.prototype) of function A, so if you modify the prototype attribute of A,
The change will affect the object instance a created by A. In the following example, the prototype of function A is modified, but it is not reflected in the instance a created by A.
var A = function(name)
{
this.name = name;
}
var a = new A('alpha');
a.name; //'alpha'
A.__proto__.max = 19880716;
a.max //undefined
——————————————————————————————————
But if I now replace the prototype property of A with a new object , the prototype a.__proto__ of the instance object still refers to the original prototype attribute of A when it was created
var A = function (name) {
this .name = name;
}
var a = new A( 'alpha ' );
a.name; //'alpha'
A.prototype = {x:23};
a.x; //null
—————————————————— ——————————————————
Translator’s Note: That is, if the object pointed to by the prototype attribute of the function is changed after the instance is created, it means that the object pointed to by the prototype attribute of the function is changed when the instance is created. The object pointed to by the instance prototype
But this does not affect the prototype of the instance that has been created.
————————————————————————————————————————-
What a default prototype looks like ?
var A = function () {};
A.prototype.constructor == A; //true
var a = new A();
a.constructor == A; //true (a's constructor property inherited from it's prototype)
What is the relationship between instance of and prototype
If the prototype of a belongs to the prototype chain of A, the value of the expression a instance of A is true. This means we can play a trick on the instance of so that it doesn't work
var A = function () {}
var a = new A();
a.__proto__ == A.prototype; //true - so instanceof A will return true
a instanceof A; //true;
//mess around with a's prototype
a.__proto__ = Function.prototype;
//a's prototype no longer in same prototype chain as A's prototype property
a instanceof A; //false
What else can you do with prototypes?
Remember that every constructor I mentioned has a prototype property that is used for every constructor it creates Instances provide prototypes. This also applies to the original constructor Function, String, etc. By extending this attribute, we can extend all instances of the specified constructor. I have used this technique in many previous articles to demonstrate function expansion. All string instances in the tracer utility article implement the times method, which copies the string itself for a specified number of times
String.prototype.times = function (count) {
Return count < 1 ? '' : new Array(count + 1).join( this );
}
"hello!" .times(3); //"hello!hello!hello!";
"please..." .times(6) ; //"please...please...please...please...please...please..."
Tell me how inheritance works through prototypes. What is a prototype chain?
Because every object and prototype has a prototype (note: a prototype is also an object). The prototype of the object points to the parent of the object, and the prototype of the parent points to the parent of the parent. We pass this through the prototype The relationships connected layer by layer form a prototype chain. The end of this chain is always the default object prototype.
a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //default object
{}.__proto__.__proto__; //null
The prototype inheritance mechanism occurs internally And it is implicit. When you want to get the value of the attribute foo of an object a, JavaScript will search for the existence of foo in the prototype chain. If it is found, it will return the value of foo, otherwise undefined will be returned.
What about assignment?
Prototype inheritance is not a player. When the attribute value is set to a.foo=’bar’, a value bar is directly set to the attribute foo of a. In order to add a property to a prototype, you need to specify the prototype directly.