1

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 Babel Experimental Mode


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

ES6 Fiddle

"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?

7
  • but your code in js different from your php Commented Jan 26, 2016 at 7:31
  • in nutshell: this.count is same as self->count and not self::count Commented Jan 26, 2016 at 7:33
  • devbank.wordpress.com/tag/static-variable-in-javascript might explain it Commented Jan 26, 2016 at 7:41
  • Yep! I am asking how can we use something like self::count in JS, but not directly accessing by class name such as: Animal.count which seems to break encapsulation principle Commented Jan 26, 2016 at 8:12
  • Static class members are not part of the object in the first place. So why would Animal.count break encapsulation? Referring to static members via self:: is basically self-deception (no pun intended). Commented Jan 26, 2016 at 8:59

3 Answers 3

2

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).

Sign up to request clarification or add additional context in comments.

1 Comment

This is not static inheritance that the OP asked about. If static inheritance was supported, you would be able to write: Animal.count, and get back a value.
2

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

Comments

0

In the Animal constructor, change this.constructor.count to Animal.count.

  • this.constructor.count refers to the Cat class counter
  • Animal.count refers to the Animals counter

I.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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.