544

Currently in ES5 many of us are using the following pattern in frameworks to create classes and class variables, which is comfy:

// ES 5
FrameWork.Class({

    variable: 'string',
    variable2: true,

    init: function(){

    },

    addItem: function(){

    }

});

In ES6 you can create classes natively, but there is no option to have class variables:

// ES6
class MyClass {
    const MY_CONST = 'string'; // <-- this is not possible in ES6
    constructor(){
        this.MY_CONST;
    }
}

Sadly, the above won't work, as classes only can contain methods.

I understand that I can this.myVar = true in constructor…but I don't want to 'junk' my constructor, especially when I have 20-30+ params for a bigger class.

I was thinking of many ways to handle this issue, but haven't yet found any good ones. (For example: create a ClassConfig handler, and pass a parameter object, which is declared separately from the class. Then the handler would attach to the class. I was thinking about WeakMaps also to integrate, somehow.)

What kind of ideas would you have to handle this situation?

Zearin
  • 1,474
  • 2
  • 17
  • 36
wintercounter
  • 7,500
  • 6
  • 32
  • 46
  • 1
    your main problem is that you'll have a repetition of `this.member = member` at your constructor with 20-30 parameters? – Theofilos Mouratidis Apr 08 '14 at 00:25
  • 1
    Can't you just use `public variable2 = true` under class? This would define it on the prototype. –  Apr 08 '14 at 08:12
  • 17
    @Θεόφιλος Μουρατίδης: Yes, and also i want to use my constructor for initialization procedures and not for variable declarations. – wintercounter Apr 08 '14 at 12:21
  • @derylius: This is the main problem, it doesn't have such feature. Even public/private usage is not decided yet in the ES6 draft. Give it a test spin: http://www.es6fiddle.net/ – wintercounter Apr 08 '14 at 12:22
  • According to the latest, it has this function: http://wiki.ecmascript.org/doku.php?id=harmony:classes –  Apr 08 '14 at 13:13
  • you can't avoid writing 20-30 parameters. Just to know so many arguments for a class isn't good. Some may be get from functions or another instance's property...For now I would write an array with all your arguments names as strings and do a loop like `this[params[i]] = arguments[i]`. If you need to make something worse try the robot like classes. You will generate the member names from `i` (eg member1, member2) in order to avoid writing your own names for members. – Theofilos Mouratidis Apr 08 '14 at 13:57
  • Yes, it's not good, i agree. But in a company with million lines of JS codes it's almost impossible to avoid such cases (5 boolean, 5 integer, 5 selector parameters and you already have 15...). I was thinking in an automatic way too, but that would make hard development because losing code completion in the IDE. – wintercounter Apr 11 '14 at 08:22
  • @wintercounter what transpiler do you use? Babel already recognizes the ES7 classProperties, and I'm using them since a while. – Buzinas Jul 27 '15 at 20:56
  • Yeah, i know that. Now i'm using riot.js with es6/typescript atm. – wintercounter Jul 29 '15 at 17:49

17 Answers17

560

2018 update:

There is now a stage 3 proposal - I am looking forward to make this answer obsolete in a few months.

In the meantime anyone using TypeScript or babel can use the syntax:

varName = value

Inside a class declaration/expression body and it will define a variable. Hopefully in a few months/weeks I'll be able to post an update.

Update: Chrome 74 now ships with this syntax working.


The notes in the ES wiki for the proposal in ES6 (maximally minimal classes) note:

There is (intentionally) no direct declarative way to define either prototype data properties (other than methods) class properties, or instance property

Class properties and prototype data properties need be created outside the declaration.

Properties specified in a class definition are assigned the same attributes as if they appeared in an object literal.

This means that what you're asking for was considered, and explicitly decided against.

but... why?

Good question. The good people of TC39 want class declarations to declare and define the capabilities of a class. Not its members. An ES6 class declaration defines its contract for its user.

Remember, a class definition defines prototype methods - defining variables on the prototype is generally not something you do. You can, of course use:

constructor(){
    this.foo = bar
}

In the constructor like you suggested. Also see the summary of the consensus.

ES7 and beyond

A new proposal for ES7 is being worked on that allows more concise instance variables through class declarations and expressions - https://esdiscuss.org/topic/es7-property-initializers

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 5
    @wintercounter the important thing to take from it is that allowing defining properties would define them on _the prototype_ like the methods and not on each instance. Maximally minimal classes is still at its very core prototypical inheritance. What you really want to do in your case is share structure and assign members for each instance. This is simply not what classes in ES6 aim for - sharing functionality. So yes, for sharing structure you'd have to stick to the old syntax. Until ES7 at least :) – Benjamin Gruenbaum Apr 11 '14 at 08:26
  • 5
    You might want to mention `static` properties – Bergi Feb 26 '15 at 22:57
  • 1
    @Bergi OP is asking about class _variables_. My outdated knowledge is that `static` is for methods and this will not do what OP asked for - or did you mean a static getter? – Benjamin Gruenbaum Feb 26 '15 at 23:03
  • 9
    Oops, brain fart. I forgot that `static` works only for methods as well. – Bergi Feb 26 '15 at 23:07
  • 694
    Maybe the good people at TC39 should name this concept something other than "class" if they don't want it to behave like the rest of the programming world expects from something named "class". – Alex Jan 04 '16 at 17:59
  • 7
    See also the "Class Fields & Static Properties" proposal (already implemented in [Babel](http://babeljs.io/): https://github.com/jeffmo/es-class-fields-and-static-properties – Matt Browne Apr 16 '16 at 00:57
  • 3
    Static properties are not a fundamental property of classes - lots of languages don't have them - Python to name one. Somehow whenever Python makes a decision like this for simplicity everyone cheers and loves it but when JS makes the same decision everyone is angry it's not exactly like _some other language_. I guess being the most widely used language in the world comes with a few problems of its own. – Benjamin Gruenbaum Aug 24 '16 at 07:23
  • 2
    @BenjaminGruenbaum Python classes can _absolutely_ have class variables (that is, variables that are attached to the _class itself_, rather than its instances). Python even has (on an opt-in basis) much more complex machinery for defining metaclasses. I _think_ the issue is that JS became the most used language because it was in the right place at the right time, but has suffered nearly 20 years' criticism because it was hastily designed. Only recently has thoughtful, considered design come to increment JS to a more human-friendly language. – Zearin Jan 26 '17 at 14:36
  • 1
    @Zearin I'm aware of that but that's not what OP means (instance variables). I find it interesting and amusing that people love Python's scoping and classes but hate JavaScript's to the point block scoping, for example, was introduced :) Thanks for the remark - it's spot on, feel free to edit if you think it's clearer now that I gave my rationale. – Benjamin Gruenbaum Jan 26 '17 at 15:12
  • BTW, if you just write `a = 2;` in your class the babel transpiler adds it as `this.a = 2;` to the constructor. I wouldn't recommend it as best practice but I found this in our code and to my surprise it works perfectly. – Erez Cohen Jun 20 '17 at 08:32
  • @ErezCohen this is the new proposal syntax and works fine – Benjamin Gruenbaum Jun 20 '17 at 14:58
  • 4
    Seems like "good people from TC39" have neither no clue about Interfaces nor what is OOP all about. – Yuriy Jul 22 '17 at 11:30
  • 2
    @Yuriy how do you figure? Note that the _current_ status is similar to Python (fields defined in constructor). Interfaces are about functionality (and not data) - and they are fully supported (as a concept) by defining methods on the object (which defines them on the prototype). I don't see any incompatibility with OOP concepts here. – Benjamin Gruenbaum Jul 22 '17 at 12:21
  • 2
    "defining variables on the prototype is generally not something you do" - Could anyone explain why that is? – Raiden616 Jan 18 '18 at 08:30
  • @Raiden616 because prototypes are not symmetric. `function Foo() {}; Foo.prototype.bar = 15; var f = new Foo(); console.log("15", f.x); f.x = 10 /* does not change prototype, changes instance variable` and it also typically works pretty slowly in JavaScript engines since the object changes its shape dynamically. – Benjamin Gruenbaum Jan 18 '18 at 09:51
  • This is a great point "The good people of TC39 want class declarations to declare and define the capabilities of a class. Not its members. " +1 emphasizing the class's outward facing interface. – Alessandro Scarlatti Apr 24 '18 at 23:52
  • Interfaces describe contracts, classes describe implementation. I wonder if they ruined our language intentionally with ES6. – inf3rno Feb 01 '20 at 22:35
140

Just to add to Benjamin's answer — class variables are possible, but you wouldn't use prototype to set them.

For a true class variable you'd want to do something like the following:

class MyClass {}
MyClass.foo = 'bar';

From within a class method that variable can be accessed as this.constructor.foo (or MyClass.foo).

These class properties would not usually be accessible from to the class instance. i.e. MyClass.foo gives 'bar' but new MyClass().foo is undefined

If you want to also have access to your class variable from an instance, you'll have to additionally define a getter:

class MyClass {
    get foo() {
        return this.constructor.foo;
    }
}

MyClass.foo = 'bar';

I've only tested this with Traceur, but I believe it will work the same in a standard implementation.

JavaScript doesn't really have classes. Even with ES6 we're looking at an object- or prototype-based language rather than a class-based language. In any function X () {}, X.prototype.constructor points back to X. When the new operator is used on X, a new object is created inheriting X.prototype. Any undefined properties in that new object (including constructor) are looked up from there. We can think of this as generating object and class properties.

lyschoening
  • 18,170
  • 11
  • 44
  • 54
  • I don't understand one thing here - I thought that class syntax and the inability to place variables directly in there was meant to prevent placing the variables in the prototype (one answer above suggested that it's intentional that the prototype should not be the place for storing variables). Yet, when we do `MyClass.foo = 'bar';` as you suggest. Isn't it doing precisely what the class restrictions should prevent us from - namely placing variables on the prototype? – tikej May 06 '21 at 10:31
  • @tikej here variable is not put on the prototype but on the constructor – Anand Bhushan May 06 '22 at 12:57
33

Babel supports class variables in ESNext, check this example:

class Foo {
  bar = 2
  static iha = 'string'
}

const foo = new Foo();
console.log(foo.bar, foo.iha, Foo.bar, Foo.iha);
// 2, undefined, undefined, 'string'
Nil
  • 174
  • 1
  • 3
  • 14
Kosmetika
  • 20,774
  • 37
  • 108
  • 172
  • 2
    You can make *bar* a [private](https://tc39.github.io/proposal-class-fields/) class variable by pretending it with "#" like this: #bar = 2; – Lonnie Best Sep 22 '18 at 03:07
32

In your example:

class MyClass {
    const MY_CONST = 'string';
    constructor(){
        this.MY_CONST;
    }
}

Because of MY_CONST is primitive https://developer.mozilla.org/en-US/docs/Glossary/Primitive we can just do:

class MyClass {
    static get MY_CONST() {
        return 'string';
    }
    get MY_CONST() {
        return this.constructor.MY_CONST;
    }
    constructor() {
        alert(this.MY_CONST === this.constructor.MY_CONST);
    }
}
alert(MyClass.MY_CONST);
new MyClass

// alert: string ; true

But if MY_CONST is reference type like static get MY_CONST() {return ['string'];} alert output is string, false. In such case delete operator can do the trick:

class MyClass {
    static get MY_CONST() {
        delete MyClass.MY_CONST;
        return MyClass.MY_CONST = 'string';
    }
    get MY_CONST() {
        return this.constructor.MY_CONST;
    }
    constructor() {
        alert(this.MY_CONST === this.constructor.MY_CONST);
    }
}
alert(MyClass.MY_CONST);
new MyClass

// alert: string ; true

And finally for class variable not const:

class MyClass {
    static get MY_CONST() {
        delete MyClass.MY_CONST;
        return MyClass.MY_CONST = 'string';
    }
    static set U_YIN_YANG(value) {
      delete MyClass.MY_CONST;
      MyClass.MY_CONST = value;
    }
    get MY_CONST() {
        return this.constructor.MY_CONST;
    }
    set MY_CONST(value) {
        this.constructor.MY_CONST = value;
    }
    constructor() {
        alert(this.MY_CONST === this.constructor.MY_CONST);
    }
}
alert(MyClass.MY_CONST);
new MyClass
// alert: string, true
MyClass.MY_CONST = ['string, 42']
alert(MyClass.MY_CONST);
new MyClass
// alert: string, 42 ; true
Oleg Mazko
  • 1,720
  • 15
  • 10
  • 5
    Please avoid the `delete` operator, if alone for performance reasons. What you actually want here is `Object.defineProperty`. – Bergi Oct 23 '15 at 04:02
  • @shinzou I was thinking the same thing. Not necessarily the OP's fault, though; it's really the language that's lacking proper mechanisms for representing data in a way that reflects its real world relationships. – user1974458 Aug 25 '19 at 19:36
19

Since your issue is mostly stylistic (not wanting to fill up the constructor with a bunch of declarations) it can be solved stylistically as well.

The way I view it, many class based languages have the constructor be a function named after the class name itself. Stylistically we could use that that to make an ES6 class that stylistically still makes sense but does not group the typical actions taking place in the constructor with all the property declarations we're doing. We simply use the actual JS constructor as the "declaration area", then make a class named function that we otherwise treat as the "other constructor stuff" area, calling it at the end of the true constructor.

"use strict";

class MyClass
{
    // only declare your properties and then call this.ClassName(); from here
    constructor(){
        this.prop1 = 'blah 1';
        this.prop2 = 'blah 2';
        this.prop3 = 'blah 3';
        this.MyClass();
    }

    // all sorts of other "constructor" stuff, no longer jumbled with declarations
    MyClass() {
        doWhatever();
    }
}

Both will be called as the new instance is constructed.

Sorta like having 2 constructors where you separate out the declarations and the other constructor actions you want to take, and stylistically makes it not too hard to understand that's what is going on too.

I find it's a nice style to use when dealing with a lot of declarations and/or a lot of actions needing to happen on instantiation and wanting to keep the two ideas distinct from each other.


NOTE: I very purposefully do not use the typical idiomatic ideas of "initializing" (like an init() or initialize() method) because those are often used differently. There is a sort of presumed difference between the idea of constructing and initializing. Working with constructors people know that they're called automatically as part of instantiation. Seeing an init method many people are going to assume without a second glance that they need to be doing something along the form of var mc = MyClass(); mc.init();, because that's how you typically initialize. I'm not trying to add an initialization process for the user of the class, I'm trying to add to the construction process of the class itself.

While some people may do a double-take for a moment, that's actually the bit of the point: it communicates to them that the intent is part of construction, even if that makes them do a bit of a double take and go "that's not how ES6 constructors work" and take a second looking at the actual constructor to go "oh, they call it at the bottom, I see", that's far better than NOT communicating that intent (or incorrectly communicating it) and probably getting a lot of people using it wrong, trying to initialize it from the outside and junk. That's very much intentional to the pattern I suggest.


For those that don't want to follow that pattern, the exact opposite can work too. Farm the declarations out to another function at the beginning. Maybe name it "properties" or "publicProperties" or something. Then put the rest of the stuff in the normal constructor.

"use strict";

class MyClass
{
    properties() {
        this.prop1 = 'blah 1';
        this.prop2 = 'blah 2';
        this.prop3 = 'blah 3';
    }

    constructor() {
        this.properties();
        doWhatever();
    }
}

Note that this second method may look cleaner but it also has an inherent problem where properties gets overridden as one class using this method extends another. You'd have to give more unique names to properties to avoid that. My first method does not have this problem because its fake half of the constructor is uniquely named after the class.

Jimbo Jonny
  • 3,549
  • 1
  • 19
  • 23
  • 1
    Please don't use a prototype method named after the class itself. That's non-idiomatic in JS, don't try to make it look like another language. If you really want to use this approach, the canonical name for the method is `init`. – Bergi Dec 22 '15 at 12:13
  • 1
    @Bergi - `init` is a pattern used often, and often meant to be called from outside the class when the outside user wants to initialize, i.e. `var b = new Thing(); b.init();`. This is a 100% stylistic choice that I'd prefer to communicate that it is a 2nd function that is automatically called by taking advantage of the patterns found in other languages. It's far less likely that someone would look at this and assume that they need to call the `MyClass` method from outside, more likely that they'd realize the intent is a 2nd method acting in construction (i.e. called by itself on instantiation). – Jimbo Jonny Dec 22 '15 at 16:20
  • 1
    Hm, I might realise that by looking at the constructor, but not from the method name `MyClass`. – Bergi Dec 22 '15 at 19:05
  • @Bergi - you very well might not realize it at first just from looking at the method name MyClass. But you wouldn't get false assumptions from it either. At worst you might not know JS and think it's the actual constructor...but since it acts like that and the only things happening in the true constructor are declarations...that actually would not be that improper of a way of treating it. – Jimbo Jonny Dec 22 '15 at 19:52
  • 1
    @Bergi - Taking a pattern from another language and applying it to JS in a way that isn't technically what's happening, but still works is not completely without precedent. You can't tell me nobody has noticed that the `$myvar` standard way of referring to variables intended to hold jQuery objects isn't conveniently similar to the pattern of having $ at the beginning of variables that so many PHP programmers are used to. Just that little implication that "yeah, it's not the same exact thing...but look...it's still a variable because that is a way variables are done in some languages!" helps. – Jimbo Jonny Dec 22 '15 at 20:00
  • 1
    I prefer your last option with the `properties()` function. However, things get a bit more complicated when extending classes so I would suggest that if you use a `properties()` function in all of your classes to declare you class properties that you prefix the method name with the class name (IE: `MyClassProperties()` in order to avoid accidentally overriding function calls within sub classes. Also, keep in mind that any calls to `super()` must be declared first in the class constructor. – Chunky Chunk Sep 26 '16 at 23:33
14

As Benjamin said in his answer, TC39 explicitly decided not to include this feature at least for ES2015. However, the consensus seems to be that they will add it in ES2016.

The syntax hasn't been decided yet, but there's a preliminary proposal for ES2016 that will allow you to declare static properties on a class.

Thanks to the magic of babel, you can use this today. Enable the class properties transform according to these instructions and you're good to go. Here's an example of the syntax:

class foo {
  static myProp = 'bar'
  someFunction() {
    console.log(this.myProp)
  }
}

This proposal is in a very early state, so be prepared to tweak your syntax as time goes on.

BonsaiOak
  • 27,741
  • 7
  • 30
  • 54
13

What about the oldschool way?

class MyClass {
     constructor(count){ 
          this.countVar = 1 + count;
     }
}
MyClass.prototype.foo = "foo";
MyClass.prototype.countVar = 0;

// ... 

var o1 = new MyClass(2); o2 = new MyClass(3);
o1.foo = "newFoo";

console.log( o1.foo,o2.foo);
console.log( o1.countVar,o2.countVar);

In constructor you mention only those vars which have to be computed. I like prototype inheritance for this feature -- it can help to save a lot of memory(in case if there are a lot of never-assigned vars).

zarkone
  • 1,335
  • 10
  • 16
  • Defining properties on the prototype is almost _never_ desirable. This is why it wasn't included in ES6 (maximally minimal) classes in the first place. – Benjamin Gruenbaum Apr 10 '14 at 13:42
  • 4
    This doesn't save memory and it just makes performance much worse than if you had declared them in the constructor. http://codereview.stackexchange.com/a/28360/9258 – Esailija Feb 13 '15 at 22:34
  • 2
    Also, this defeats the purpose of using ES6 classes in the first place. As it stands, it seems hardly possible to use ES6 classes like real oop classes, which is somewhat disappointing... – Kokodoko Dec 22 '15 at 14:45
  • 4
    @Kokodoko real oop -- you mean, like i.e. in Java? I agree, I've noticed that a lot of people angry to JS because they try to use it like Java, like they get used to, because JS syntax looks similar, and they assume that it works the same way... But from the inside, it is quite differ, as we know. – zarkone Dec 23 '15 at 06:01
  • 2
    It's not just about language syntax though. The OOP philosophy lends itself quite well to programming in general - especially when creating apps and games. JS has traditionally been implemented in building webpages which is quite different. Somehow those two approaches need to come together, since the web is becoming more about apps as well. – Kokodoko Dec 23 '15 at 09:47
  • 1
    @Kokodoko Just because it's a *different* OOP doesn't mean it *isn't* OOP. Prototypes are a 100%-valid OOP approach; nobody's going to call Self "non-OOP" because it uses prototypes. Not matching another OOP paradigm means just that: it's different. – Dave Newton May 09 '17 at 19:42
  • @DaveNewton it's just not OOP. No interfaces, lack of encapsulation, primitive extend, etc. Just because you play with objects doesn't make it adhere to OOP paradigms. Now, this doesn't make it worse, just not OOP – Nertan Lucian Jun 19 '18 at 19:44
  • 1
    @NertanLucian Interfaces: not required by OOP at all. Encapsulation: JS has it. I don't know what "primitive extend" means. "Etc." is non-actionable. Your definition of the "OOP paradigm" seems tied to particular curly-brace OOP languages, which is a subset of OOP languages and paradigms. – Dave Newton Jun 19 '18 at 20:38
11

[Long thread, not sure if its already listed as an option...].
A simple alternative for contsants only, would be defining the const outside of class. This will be accessible only from the module itself, unless accompanied with a getter.
This way prototype isn't littered and you get the const.

// will be accessible only from the module itself
const MY_CONST = 'string'; 
class MyClass {

    // optional, if external access is desired
    static get MY_CONST(){return MY_CONST;}

    // access example
    static someMethod(){
        console.log(MY_CONST);
    }
}
Hertzel Guinness
  • 5,912
  • 3
  • 38
  • 43
  • What happens if you a) use a `var` instead of `const` 2) use multiple instances of this class? Then the external variables will be changed with each instance of the class – nick carraway Apr 24 '19 at 20:49
  • 1
    fail point @nickcarraway, my offer stands for const only, not as the question titled. – Hertzel Guinness Apr 25 '19 at 19:32
10

ES7 class member syntax:

ES7 has a solution for 'junking' your constructor function. Here is an example:

class Car {
  
  wheels = 4;
  weight = 100;

}

const car = new Car();
console.log(car.wheels, car.weight);

The above example would look the following in ES6:

class Car {

  constructor() {
    this.wheels = 4;
    this.weight = 100;
  }

}

const car = new Car();
console.log(car.wheels, car.weight);

Be aware when using this that this syntax might not be supported by all browsers and might have to be transpiled an earlier version of JS.

Bonus: an object factory:

function generateCar(wheels, weight) {

  class Car {

    constructor() {}

    wheels = wheels;
    weight = weight;

  }

  return new Car();

}


const car1 = generateCar(4, 50);
const car2 = generateCar(6, 100);

console.log(car1.wheels, car1.weight);
console.log(car2.wheels, car2.weight);
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
5

You can mimic es6 classes behaviour... and use your class variables :)

Look mum... no classes!

// Helper
const $constructor = Symbol();
const $extends = (parent, child) =>
  Object.assign(Object.create(parent), child);
const $new = (object, ...args) => {
  let instance = Object.create(object);
  instance[$constructor].call(instance, ...args);
  return instance;
}
const $super = (parent, context, ...args) => {
  parent[$constructor].call(context, ...args)
}
// class
var Foo = {
  classVariable: true,

  // constructor
  [$constructor](who){
    this.me = who;
    this.species = 'fufel';
  },

  // methods
  identify(){
    return 'I am ' + this.me;
  }
}

// class extends Foo
var Bar = $extends(Foo, {

  // constructor
  [$constructor](who){
    $super(Foo, this, who);
    this.subtype = 'barashek';
  },

  // methods
  speak(){
    console.log('Hello, ' + this.identify());
  },
  bark(num){
    console.log('Woof');
  }
});

var a1 = $new(Foo, 'a1');
var b1 = $new(Bar, 'b1');
console.log(a1, b1);
console.log('b1.classVariable', b1.classVariable);

I put it on GitHub

Ruslan
  • 199
  • 3
  • 5
1

Still you can't declare any classes like in another programming languages. But you can create as many class variables. But problem is scope of class object. So According to me, Best way OOP Programming in ES6 Javascript:-

class foo{
   constructor(){
     //decalre your all variables
     this.MY_CONST = 3.14;
     this.x = 5;
     this.y = 7;
     // or call another method to declare more variables outside from constructor.
     // now create method level object reference and public level property
     this.MySelf = this;
     // you can also use var modifier rather than property but that is not working good
     let self = this.MySelf;
     //code ......... 
   }
   set MySelf(v){
      this.mySelf = v;
   }
   get MySelf(v){
      return this.mySelf;
   }
   myMethod(cd){
      // now use as object reference it in any method of class
      let self = this.MySelf;
      // now use self as object reference in code
   }
}
Sartaj
  • 139
  • 5
1

If its only the cluttering what gives the problem in the constructor why not implement a initialize method that intializes the variables. This is a normal thing to do when the constructor gets to full with unnecessary stuff. Even in typed program languages like C# its normal convention to add an Initialize method to handle that.

1

Just define a getter.

class MyClass
{
  get MY_CONST () { return 'string'; }

  constructor ()
  {
    console.log ("MyClass MY_CONST:", this.MY_CONST);
  }
}

var obj = new MyClass();
ceving
  • 21,900
  • 13
  • 104
  • 178
0

The way I solved this, which is another option (if you have jQuery available), was to Define the fields in an old-school object and then extend the class with that object. I also didn't want to pepper the constructor with assignments, this appeared to be a neat solution.

function MyClassFields(){
    this.createdAt = new Date();
}

MyClassFields.prototype = {
    id : '',
    type : '',
    title : '',
    createdAt : null,
};

class MyClass {
    constructor() {
        $.extend(this,new MyClassFields());
    }
};

-- Update Following Bergi's comment.

No JQuery Version:

class SavedSearch  {
    constructor() {
        Object.assign(this,{
            id : '',
            type : '',
            title : '',
            createdAt: new Date(),
        });

    }
}

You still do end up with 'fat' constructor, but at least its all in one class and assigned in one hit.

EDIT #2: I've now gone full circle and am now assigning values in the constructor, e.g.

class SavedSearch  {
    constructor() {
        this.id = '';
        this.type = '';
        this.title = '';
        this.createdAt = new Date();
    }
}

Why? Simple really, using the above plus some JSdoc comments, PHPStorm was able to perform code completion on the properties. Assigning all the vars in one hit was nice, but the inability to code complete the properties, imo, isn't worth the (almost certainly minuscule) performance benefit.

Steve Childs
  • 1,832
  • 2
  • 20
  • 26
  • 2
    If you can do `class` syntax, you also can do `Object.assign`. No need for jQuery. – Bergi May 10 '17 at 23:23
  • I don't see any point to make `MyClassFields` a constructor - it doesn't have any methods. Can you elaborate why you did this (instead of, say, a simple factory function that returns an object literal)? – Bergi May 10 '17 at 23:27
  • @Bergi - Probably force of habit rather than anything else, to be honest. Also nice call about Object.assign - didn't know about that! – Steve Childs May 11 '17 at 07:32
0

Well, you can declare variables inside the Constructor.

class Foo {
    constructor() {
        var name = "foo"
        this.method = function() {
            return name
        }
    }
}

var foo = new Foo()

foo.method()
Osama Xäwãñz
  • 437
  • 2
  • 8
  • 21
  • 1
    You'll need to create an instance of this class to use this variable. Static functions cannot access that variable – Aditya Aug 30 '18 at 12:35
0

Recent browsers as of 2021 (not IE, see MDN browser chart) implement Public class fields which seems to be what you're looking for:

class MyClass {
  static foo = 3;
}

console.log(MyClass.foo);

However apparently it's not possible to make this a const: Declaring static constants in ES6 classes?

A static getter looks pretty close:

class MyClass {
  static get CONST() {
    return 3;
  }
}

MyClass.CONST = 4; // property unaffected
console.log(MyClass.CONST);
qwr
  • 9,525
  • 5
  • 58
  • 102
-1

This is a bit hackish combo of static and get works for me

class ConstantThingy{
        static get NO_REENTER__INIT() {
            if(ConstantThingy._NO_REENTER__INIT== null){
                ConstantThingy._NO_REENTER__INIT = new ConstantThingy(false,true);
            }
            return ConstantThingy._NO_REENTER__INIT;
        }
}

elsewhere used

var conf = ConstantThingy.NO_REENTER__INIT;
if(conf.init)...
TroyWorks
  • 411
  • 8
  • 16
  • 7
    I'd recommend `singleton_instance` as a property name so that everybody understands what you are doing here. – Bergi Sep 12 '15 at 11:35