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?
The static keyword defines static methods for classes. Static methods are called directly on the class ( Car from the example above) - without creating an instance/object ( mycar ) of the class.
"Static" properties are simply properties on the constructor function objects. They don't have anything to do with the JavaScript inheritance scheme.
What is prototype inheritance in JavaScript? In prototypical inheritance, prototypes are object instances to which child instances delegate undefined properties. In contrast, classes in classical inheritance are type definitions, from which child classes inherit methods and properties during instantiation.
Static properties are used when we'd like to store class-level data, also not bound to an instance.
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?
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:
function Employee() {
}
Employee.prototype.count = 0;
As of the code above, there is an object in memory for Employee.prototype
. Some ASCII art:
+−−−−−−−−−−−−−−−−−−−−+ | Employee.prototype | +−−−−−−−−−−−−−−−−−−−−+ | count: 0 | +−−−−−−−−−−−−−−−−−−−−+
Then we do this:
var e = new Employee();
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
:
console.log(e.count);
...since e
doesn't have its own property called count
, the engine looks at e
's prototype to find it, finds it, and uses that value.
However, when we do this:
e.count += 1; // Or more idiomatically, `++e.count;` or `e.count++;`
That assigns a value to count
on the e
instance. e
now has its own copy of count
:
+−−−−−−−−−−−−−−−+ | e | +−−−−−−−−−−−−−−−+ | count: 1 | +−−−−−−−−−−−−−−−−−−−−+ | [[Prototype]] |−−−−−−−−−>| Employee.prototype | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | count: 0 | +−−−−−−−−−−−−−−−−−−−−+
Now if you query e.count
:
console.log(e.count);
...the engine finds count
on e
, and doesn't look at the prototype.
You can see this effect in code:
function Employee() {
}
Employee.prototype.count = 0;
var e = new Employee();
console.log(e.hasOwnProperty('count')); // false
e.count += 1;
console.log(e.hasOwnProperty('count')); // true
console.log(e.count); // 1
console.log(Employee.prototype.count); // 0
This is also fun:
var e = new Employee();
console.log(e.count); // 0
++Employee.prototype.count;
console.log(e.count); // 1
Since e
doesn't (yet) have its own copy of count
, if we actually increment the property on Employee.prototype
, we see the updated value whether we ask for it directly (Employee.prototype.count
) or indirectly (e.count
).
Final note on this: If e
gets its own copy of a property, you can remove it again:
var e = new Employee();
console.log(e.count); // 0, because it's using `Employee.prototype.count`
++e.count; // Now `e` has its own `count` property
console.log(e.count); // 1, `e`'s own `count`
delete e.count; // Now `e` doesn't have a `count` property anymore
console.log(e.count); // 0, we're back to using `Employee.prototype.count`
delete
would be more properly called remove
. It removes properties from objects.
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?
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:
var Employee = (function() {
var sharedVariable = 0;
function Employee() {
++sharedVariable;
console.log("sharedVariable = " + sharedVariable);
}
return Employee;
})();
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:
new Employee();
new Employee();
new Employee();
new Employee();
outputs
1 2 3 4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With