Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript: class.property vs class.prototype.property to emulate static properties

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?

like image 694
riju Avatar asked Nov 21 '12 04:11

riju


People also ask

Which keyword's are required to create a static property within a class?

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.

Are static properties inherited JavaScript?

"Static" properties are simply properties on the constructor function objects. They don't have anything to do with the JavaScript inheritance scheme.

What is class prototype JavaScript?

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.

When should a property be static?

Static properties are used when we'd like to store class-level data, also not bound to an instance.


1 Answers

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:

  1. Exactly as you've done it, Employee.sharedProperty.

  2. 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
like image 169
T.J. Crowder Avatar answered Oct 04 '22 17:10

T.J. Crowder