Reputation: 32354
In prototypal languages object can basically clone each other.
So, lets say we have a constructor function:
Bla = function()
{
this.a = 1;
}
I can create a new instance of that object like this: x = new Bla();
. Now, x.a
returns 1.
If I were to write Bla.prototype.b = 2
, then x.b
would return 2. But, why? If x "cloned" Bla, why can't I just say that Bla.b = 2
, without referencing the Bla.prototype
, and still get the same functionality? Does this have something to do with the this
keyword?
Upvotes: 4
Views: 469
Reputation: 20540
ECMAScript (JavaScript) supports "prototype-based inheritance". This means there is no differentiation between "class" and "instance" in JS.
Opposed to OOP in other languages, in JS a "class" and "instance" are basically the same thing:
When you define Something
, it is instanciated immediately (ready to use), but can also serve as a "prototype" to clone the initial(!) definition of the object Someting
for another instance with the same properties and methods.
In ECMAScript, everything is an object, even the objects initial definition. In other OOP languages, you have a "class" for the definition part.
The prototype
object is for the case when you want to extend the prototype of "Something" (read: "class" Something
) after the initial definition and add the new property / function to all current and future instances of Something
.
If you are confused now, i think this code example may help to spot the difference:
// when defining "Something", the initial definition is copied into the "prototype"
var Something = function()
{
this.a = 1;
}
// we can either modify the "prototype" of "Something"
Something.prototype.b = 2;
// or we can modify the instance of "Something"
Something.c = 3;
// now lets experiment with this..
var x = new Something(); // read: "clone the prototype of 'Something' into variable 'x'"
console.log(x.b); // logs "2" -- "b" was added to the prototype, available to all instances
console.log(x.c); // undefined -- "c" only exists in the instance "Something"
console.log(Something.c); // logs "3" -- "Something" is an object, just like our new instance 'x'
// also note this:
Something.a = 1337;
var y = new Something();
console.log(y.a); // logs "1" -- because the "prototype" was cloned,
// opposed to the current state of object "Something"
console.log(Something.a); // logs "1337"
As you see in the last example, the concept of "prototype" is necessary to avoid cloning the current "state" of your object.
If it wouldn't be implemented this way, you would possibly end up with weird effects, because if the original object "Something" was used / modified before you clone it, then the current state would be copied as well. That is why the language designers went for the prototype
construct.
Always remember: "Something" isn't a static definition, like "classes" are in other OOP languages.
The ECMAScript specification says about prototype
:
A prototype is an object used to implement structure, state, and behaviour inheritance in ECMAScript. When a constructor creates an object, that object implicitly references the constructor's associated prototype for the purpose of resolving property references. The constructor's associated prototype can be referenced by the program expression constructor.prototype, and properties added to an object's prototype are shared, through inheritance, by all objects sharing the prototype.
Some JS frameworks like the equally named "prototype" make heavy use of this feature to extend the functionality of Javascripts built-in objects.
For example, it extends the native array
object with the method forEach
, to add this missing feature to JS:
Array.prototype.forEach = function each(iterator, context) {
for (var i = 0, length = this.length >>> 0; i < length; i++) {
if (i in this) iterator.call(context, this[i], i, this);
}
}
Upvotes: 10
Reputation: 12534
It has to do with the difference between a class and an instance. x is an instance of the class Bla. If you set x.b = 2, you add/set a property b for that instance. If you set b on the prototype of b, you create a property for that class (and for each existing instance as well). That at the same time is the difference between setting it in the constructor as is done with a here: when a is changed on an instance, it's ...well changed. If b is changed, the prototype b still exists with its old value, but a new property b is created for that instance with the new value. (This can be useful for resetting to default values)
edit Realized that text sometimes is a lot less clear than code samples, so added a complete sample that I hope illustrates the difference
function bla(){
this.a= 1;
}
var x = new bla(),
y= new bla();
bla.prototype.b= 2;
x.c = 3;
//x already exists, but b is still set
//by setting the prototype all existing instances are changed
console.log(x.b); //2
console.log(y.b); //2
//because c has been explicitly set, it only exists on instance x
console.log(x.c); //3
console.log(y.c); //undefined
x.b = 6; //at this point
//as mentioned, setting a property on an instance, only affects
//that instance
console.log(x.b); //6
console.log(y.b); //2
//but, because b is also a prototype property, it can be 'reset'
//by deleting the instance property
delete x.b; //removes the instance b
delete y.b; //on y this does nothing, because only the prototype property exists
console.log(x.b); //2 (reset to prototype)
console.log(y.b); //2
//the final difference, because a is a class bla property, and
//not of its prototype, deleting property 'a', will actually cause a remove
delete x.a;
console.log(x.a); //undefined
Upvotes: 4