7

I've been hunting around for a clear answer to this, and most of what pops up still relates to the old (or should I say "traditional") way of defining classes using function.

According to this SO answer,

Class properties are not supported in ES2015.

As far as I can tell, the only way to add a static variable to a class is like:

https://jsfiddle.net/abalter/fknwx3n4/

class C {

  constructor(x) {
    console.log("in constructor " + x);
    this.x = x;
    this.add(this.x);
  }

  add(x) {
    console.log("in add " + x);
    C.alist.push(x);
  }

  show() {
    console.log("in show");
    console.log(C.alist);
  }
}

// MUST be done outside of actual class definition.
C.alist = [];

c1 = new C(5);
c1.show();
c2 = new C(10);
c1.show();
c2.show();

Is this the end of the story? Just seems so strange to not be able to do it INSIDE the class definition.

Community
  • 1
  • 1
abalter
  • 9,663
  • 17
  • 90
  • 145
  • Yes, that's the end of the story. There is nothing wrong with putting such properties after the class definition, btw – Bergi Jun 23 '16 at 04:57
  • ES7 supports class properties. But no, that's not the end of story in ES2015. The array could be set in the constructor as the instance property. – Ram Jun 23 '16 at 04:58
  • Your example use case is weird. Mutable static properties are an instance of the singleton antipattern. – Bergi Jun 23 '16 at 04:58
  • 1
    @Vohuman: ES7 does not, and probably ES8 won't either. – Bergi Jun 23 '16 at 04:58
  • @Bergi not sure what you mean. Suppose I have a Store class with branches that are instances. A class variable belonging to Store can be added to and viewed by all instances. What better way is there for all branches of the store to know the total stock – abalter Jun 23 '16 at 05:11
  • @Bergi I shouldn't have written than "ES7 supports ..." as it's not a recommendation yet. I had seen some "ES7 classes" that use such properties, probably compiled by a transformer like this: https://babeljs.io/docs/plugins/transform-class-properties/ and thought that JS is going to support this. I'm not sure about ES7 as I don't follow the development stages of it. – Ram Jun 23 '16 at 05:23
  • 1
    @Vohuman [This proposal is still on stage 1](https://github.com/tc39/proposals). It has been for a long time. I am not sure why it is not moving forward as it looks like a lot of people would like to see it. – Quentin Roy Jun 23 '16 at 05:31
  • @Bergi Can you elaborate on the singleton bit (or cite something)? I'm not aware of static properties being instantly considered a singleton. (why else would people want them?) I just call it encapsulation. – 4castle Jun 23 '16 at 06:15
  • @4castle: You should have separate classes for Stores and Branches then. If you model the total stock as a static property, you can essentially have only one store (globally). That's a singleton. – Bergi Jun 23 '16 at 07:44
  • @Bergi I'm neither an expert in OOP terminology nor OOP programming. But in my Java classes we distinctly covered the idea of having a class with instances that share data. I believe one of the examples in the book was a company with total company profit and branches with their own (contributing) profits. Does having one shared property make the ENTIRE class a singleton? [Wikipedia](https://en.wikipedia.org/wiki/Singleton_pattern) says "In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to ONE object." (my emphasis) – abalter Jun 23 '16 at 16:24
  • 1
    @abalter: No, I meant that only `C.alist = [];` is the singleton object. Of course, in Java where everything is a class, you'd need an extra class to create singleton instances, in JS creating objects directly is so much simpler. – Bergi Jun 23 '16 at 17:50
  • How about using static **_getters_ and _setters_**? – Константин Ван Apr 07 '18 at 18:58

2 Answers2

2

You could call a static function that initializes all the static members immediately after the class is defined, and then optionally delete that function. (Possibly resetting static variables would be a feature?)

This would allow you to keep all of your static variables inside the class declaration.

class C {
  static init() {
    C.alist = [];
  }

  constructor(x) {…}
  add(x) {…}
  show() {…}
}
C.init();
delete C.init;

Another option is to initialize static variables in the constructor, but this requires that at least one object be instantiated before the static variables can be used.

class C {
  constructor(x) {
    C.alist = C.alist || [];
    …
  }
  add(x) {…}
  show() {…}
}
4castle
  • 32,613
  • 11
  • 69
  • 106
  • Interesting...Also a bit awkward, but at least it is in the constructor. – abalter Jun 23 '16 at 05:13
  • @abalter I have updated. Maybe you will find this other option less awkward? It would also allow you to ***re***set all the static variables later. – 4castle Jun 23 '16 at 05:18
  • I would code `this.alist = []` and not `C.alist = []`. Why should instances share the same information? That's misusing a class. – Ram Jun 23 '16 at 05:27
  • 1
    @Vohuman Are you saying it's misusing a JS class? Because in OOP it's perfectly legal and very common. – 4castle Jun 23 '16 at 05:28
  • @abalter I've made several more edits, and I'm starting to think that this is a really good idea. Does anyone see any drawbacks/improvements? – 4castle Jun 23 '16 at 05:50
  • @4castle--Darn. I liked the former better. Now I still have to do stuff after the class definition. I just can't understand why the powers that be would allow static methods, but not static properties. Anyway, just for comparison for future viewers, I've implemented your first suggestion here https://jsfiddle.net/abalter/zxcydnsa/ – abalter Jun 23 '16 at 16:31
  • 1
    @abalter I'll definitely put the old answer back in. I kinda prefer this though because it allows for syntax that feels a little more natural, and the only part that remains outside of the class is a bit of helper code. I was a bit unhappy with how my other solution required instantiating an object too. – 4castle Jun 23 '16 at 21:09
0

If all you care about is stylistic encapsulation of the class and its static properties in one structure, you should consider using the module pattern (just like we used it in ES5 to enclose the constructor and the prototype).

In ES6, there is also Object.assign that you could use for this:

const C = Object.assign(class {
    constructor() {
        …
    }
    methods() { … }
    …
}, {
    of(x) { … },
    static_methods() {…},
    …
    static_property: …
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I have mixed feelings. It works, and even allows separation of concerns to a degree, but loses much of the syntactic sugar. Would either of our solutions suffer when extending the class? – 4castle Jun 23 '16 at 12:57
  • No, you still can use `extends C` without problems. The only syntactic sugar you lose is `super` when putting your static methods in the object literal, you'd have to use `static static_method() { super…}` in the class body for that. – Bergi Jun 23 '16 at 17:54
  • In case anybody cares, this is vaguely reminiscent of the pattern used by Ember with `reopenClass`. –  Sep 04 '16 at 08:06