I have been trying to emulate static properties in javascript.
It has been mentioned in several places that class.prototype.property will be static across all objects inheriting from the class. But my POC says otherwise. Please take a look:
Using Class.prototype.property
//Employee class
function Employee() {
this.getCount = function(){
return this.count;
};
this.count += 1;
}
Employee.prototype.count = 3;
var emp = [], i;
for (i = 0; i < 3; i++) {
emp[i] = new Employee();
console.log("employee count is "+ emp[i].getCount());
}
/*Output is:
employee count is 4
employee count is 4
employee count is 4*/
My Question #1: If this were to be static, then shouldn’t the value of count have been 4,5,6,etc as all the objects share the same count variable?
Then I did another POC with Class.prototype and I think this to be static.
Using Class.property
//Employee class
function Employee() {
this.getCount = function(){
return Employee.count;
};
Employee.count++;
}
Employee.count = 3;
var emp = [], i;
for (i = 0; i < 3; i++) {
emp[i] = new Employee();
console.log("employee count is "+ emp[i].getCount());
}
/*Output is:
employee count is 4
employee count is 5
employee count is 6*/
My Question #2: Nowhere I have seen class.property being used directly. How exactly are static variables made in javascript keeping in mind my above code?
Or Have I coded something wrong here? Is this not the correct perception?
Prototype properties are shared across instances, but if an instance has its own copy of the property, it will use that instead. Assigning to the property on the instance gives it its own copy, and so it doesn’t use the prototype’s anymore.
The
+=,++, and similar operators result in assignments, and so they cause this behavior as well.Consider:
As of the code above, there is an object in memory for
Employee.prototype. Some ASCII art:Then we do this:
Now there’s a second object in memory, which has a reference back to
Employee.prototype:+−−−−−−−−−−−−−−−+ | e | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] |−−−−−−−−−>| Employee.prototype | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | count: 0 | +−−−−−−−−−−−−−−−−−−−−+And if you query
e.count:…since
edoesn’t have its own property calledcount, the engine looks ate‘s prototype to find it, finds it, and uses that value.However, when we do this:
That assigns a value to
counton theeinstance.enow has its own copy ofcount:+−−−−−−−−−−−−−−−+ | e | +−−−−−−−−−−−−−−−+ | count: 1 | +−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] |−−−−−−−−−>| Employee.prototype | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | count: 0 | +−−−−−−−−−−−−−−−−−−−−+Now if you query
e.count:…the engine finds
countone, and doesn’t look at the prototype.You can see this effect in code:
This is also fun:
Since
edoesn’t (yet) have its own copy ofcount, if we actually increment the property onEmployee.prototype, we see the updated value whether we ask for it directly (Employee.prototype.count) or indirectly (e.count).Final note on this: If
egets its own copy of a property, you can remove it again:deletewould be more properly calledremove. It removes properties from objects.Two ways:
Exactly as you’ve done it,
Employee.sharedProperty.By defining the entire “class” inside a function, and using local variables within that function:
All functions defined within that outer scoping function will have access to the local variables defined within it. So there’s just one variable, the local within the one call to that outer function that creates
Employee.Then, this code:
outputs