Reputation: 21
I'm trying to figure out how does Javascript completely support OOP. Luckily I can find some clue through Babel and know how it do downward compatibility to ES5.
But I found the static variable behaviors strange in inheritance.
For example, I want to remember global properties in superclass. But it seems static variable accessed from subclass is not actually refers to superclass. Is this reasonable in classical OOP?
class Animal {
constructor(){
this.constructor.count += 1;
console.log('An animal was born');
}
static count = 0;
static sum = function(){
console.log('There are', this.count, 'animals');
}
}
class Cat extends Animal{
constructor(){
super(); // throws exception when not called
console.log(' -- the animal is a cat');
}
}
var cat1 = new Cat();
var cat2 = new Cat();
Cat.sum(); // should be 2
Animal.sum(); // should be 2, but result is 0
In the above was expermental syntax. Then I saw an article says static property is not supported in ES6 yet. So I follow his example rewriting into static method (getter/setter), style, but still got no idea.....
class Animal {
constructor(){
this.constructor.countOne();
console.log('An animal was born');
}
static countOne(){
this.count = (this.count||0)+1;
}
static sum(){
console.log('There are', this.count, 'animals');
}
}
Animal.count = 0; // Remove this, Animal.sum() will be undefined
class Cat extends Animal{
constructor(){
super();
console.log(' -- the animal is a cat');
}
}
var cat1 = new Cat();
var cat2 = new Cat();
Cat.sum(); // should be 2
Animal.sum(); // should be 2, but result is 0
"this" refers to subclass, not superclass, result is the same...
Furthermore, I try the same code in PHP, then I got expected result:
class Animal{
static $count = 0;
static function sum(){
echo "There are " . self::$count . " animals <br>";
}
public function __construct(){
self::$count++;
echo "An animal was born <br>";
}
}
class Cat extends Animal{
public function __construct(){
parent::__construct();
echo " - the animal is a cat <br>";
}
}
$cat = new Cat();
$cat = new Cat();
$cat = new Cat();
Cat::sum(); // is 3
Animal::sum(); // is 3
So far, should we say static variable inheritance is not supported by Javascript? even in ECMA6?
Is there any graceful solution?
Upvotes: 1
Views: 4557
Reputation: 2318
In the Animal
constructor, change this.constructor.count
to Animal.count
.
this.constructor.count
refers to the Cat
class counterAnimal.count
refers to the Animal
s counterI.e.:
class Animal {
constructor(){
Animal.count += 1;
console.log('An animal was born');
}
The main point is each class has its own static variable, i.e. its not shared. JavaScript doesnt support classes in the traditional sense, they say its syntatic sugar over the object prototype model it uses. You may find this link useful: https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/objects-classes
Upvotes: 0
Reputation: 54026
There is an alternative way to provide static properties and that is via closure. By wrapping your class definitions inside a function you can scope variables only to your class, effectively creating a private static variable.
For example
"use strict";
var log =function(d){console.log(d)}; // lazy zoo keeper
// need to define the intermediate container
// Ill call it zoo.
var zoo = (function() {
// now create the private static property
var count=0; // function scoped
class Animal {
constructor(){
count += 1; // count instances
log('An animal was born');
}
static sum(){ // create the static method of interagation
log('There are'+count+'animals');
}
}
class Cat extends Animal{
whatAreYou(){log("I am a cat ")};
}
// now return the classes you want to expose
return {
Animal:Animal,
Cat:Cat,
};
})(); // call the function to create a Zoo
// now you can make the the Animal and Cat public or you could
// keep zoo and pass it to another scope and have them private
// where you want.
var Animal = zoo.Animal;
var Cat = zoo.Cat;
// Use static function befor there are any instances of Animal or Cat
Animal.sum(); // displays 0
var a = new Animal(); // or new zoo.Animal();
var c = new Cat();
// access static function sum to display content of private and static (closure) property count;
Cat.sum(); // 2
Animal.sum(); // 2
Upvotes: 2
Reputation: 51841
You can access static members like:
Animal.count;
Animal.countOne();
Animal.sum();
In your 2nd example when you create new cat, this
refers to new cat object and this.constructor
refers to Cat function (even if it is called from super constructor).
Upvotes: 2