Home Cryptocurency ExchangesUnderstanding JavaScript Prototypes. – JavaScript, JavaScript…
Understanding JavaScript Prototypes. – JavaScript, JavaScript…

Understanding JavaScript Prototypes. – JavaScript, JavaScript…

(en Españolрусском中文)

JavaScript’s prototype object generates confusion wherever it goes. Seasoned JavaScript professionals, even authors frequently exhibit a limited understanding of the concept. I believe a lot of the trouble stems from our earliest encounters with prototypes, which almost always relate to new, constructor and the very misleading prototype property attached to functions. In fact prototype is a remarkably simple concept. To understand it better, we just need to forget what we ‘learned’ about constructor prototypes and start again from first principles.

What is a prototype?

A prototype is an object from which other objects inherit properties

Can any object be a prototype?

Yes.

Which objects have prototypes?

Every object has a prototype by default. Since prototypes are themselves objects, every prototype has a prototype too. (There is only one exception, the default object prototype at the top of every prototype chain. More on prototype chains later)

OK back up, what is an object again?

An object in JavaScript is any unordered collection of key-value pairs. If it’s not a primitive (undefined, null, boolean, number or string) it’s an object.

You said every object has a prototype. But when I write ({}).prototype I get undefined. Are you crazy?

Forget everything you learned about the prototype property – it’s probably the biggest source of confusion about prototypes. The true prototype of an object is held by the internal [[Prototype]] property. ECMA 5 introduces the standard accessor Object.getPrototypeOf(object) which to-date is implemented in Firefox, Safari, Chrome and IE9. In addition all browsers except IE support the non-standard accessor __proto__. Failing that we can ask the object’s constructor for its prototype property.

var a = {};

Object.getPrototypeOf(a); //[object Object]

a.__proto__; //[object Object]

//all browsers
//(but only if constructor.prototype has not been replaced and fails with Object.create)
a.constructor.prototype; //[object Object]

Ok fine, but false is a primitive, so why does false.__proto__ return a value?

When a primitive is asked for it’s prototype it will be coerced to an object.

//
false.__proto__ === Boolean(false).__proto__; //true

I want to use prototypes for inheritance. What do I do now?

It rarely makes sense to set a prototype for one instance and only one instance, since it would be equally efficient just to add properties directly to the instance itself. I suppose if we have created a one off object which we would like to share the functionality of an established object, such as Array, we might do something like this (in __proto__ supporting browsers).

var a = {};
a.__proto__ = Array.prototype;
a.length; //0

But the real power of prototype is seen when multiple instances share a common prototype. Properties of the prototype object are defined once but inherited by all instances which reference it. The implications for performance and maintenance are obvious and significant.

So is this where constructors come in?

Yes. Constructors provide a convenient cross-browser mechanism for assigning a common prototype on instance creation.

Just before you give an example I need to know what this constructor.prototype property is all about?

OK. Firstly JavaScript makes no distinction between constructors and other functions, so every function gets a prototype property (built-in function excepted). Conversely, anything that is not a function does not have such a property.

//function will never be a constructor but it has a prototype property anyway
(new Function()).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

So now the definition: A function’s prototype property is the object that will be assigned as the prototype to all instances created when this function is used as a constructor.

It’s important to understand that a function’s prototype property has nothing to do with it’s 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

Example please?

You’ve probably seen and used this a hundred times but here it is once again, maybe now with added perspective.

//Constructor. <em>this</em> 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() {
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

That’s great. And if I change the constructor’s prototype, even existing instances will have access to the latest version right?

Well….not exactly. If I modify the existing prototype’s property then this is true, because a.__proto__ is a reference to the object defined by A.prototype at the time it was created.

var A = function(name) {
this.name = name;
}

var a = new A(‘alpha’);
a.name; //’alpha’

A.prototype.x = 23;

a.x; //23

But if I replace the prototype property with a new object, a.__proto__ still references the original object.

var A = function(name) {
this.name = name;
}

var a = new A(‘alpha’);
a.name; //’alpha’

A.prototype = {x:23};

a.x; //null

What does a default prototype look like?

An object with one property, the constructor.

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 does instanceof have to do with prototype?

The expression a instanceof A will answer true if A’s prototype property occurs in a’s prototype chain. This means we can trick instanceof into failing

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

So what else can I do with prototypes?

Remember I said that every constructor has a prototype property which it uses to assign prototypes to all instances it generates? Well that applies to native constructors too such as Function and String. By extending (not replacing!) this property we get to update the prototype of every instance of the given type.

I’ve used this technique in numerous previous posts to demonstrate function augmentation. For example the tracer utility I introduced in my last post needed all string instances to implement times, which returns a given string duplicated a specified number of times

String.prototype.times = function(count) {
return count &lt; 1 ? ” : new Array(count + 1).join(this);
}

“hello!”.times(3); //”hello!hello!hello!”;
“please…”.times(6); //”please…please…please…please…please…please…”

Tell me more about how inheritance works with prototypes. What’s a prototype chain?

Since every object and every prototype (bar one) has a prototype, we can think of a succession of objects linked together to form a prototype chain. The end of the chain is always the default object’s prototype.

a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //default object
{}.__proto__.__proto__; //null

The prototypical inheritance mechanism is internal and non-explicit. When object a is asked to evaluate property foo, JavaScript walks the prototype chain (starting with object a itself), checking each link in the chain for the presence of property foo. If and when foo is found it is returned, otherwise undefined is returned.

What about assigning values?

Prototypical inheritance is not a player when property values are set. a.foo = ‘bar’ will always be assigned directly to the foo property of a. To assign a property to a prototype you need to address the prototype directly.

And that about covers it. I feel I have the upper hand on the prototype concept but my opinion is by no means the final word. Please feel free to tell me about errors or disagreements.

Where can I get more information on protoypes?

I recommend this excellent article by Dmitry A. Soshnikov

Source

Leave a Reply

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

Human Verification: In order to verify that you are a human and not a spam bot, please enter the answer into the following box below based on the instructions contained in the graphic.