How to add mixins to ES6 javascript classes? - javascript

In an ES6 class with some instance variables and methods, how can you add a mixin to it? I've given an example below, though I don't know if the syntax for the mixin object is correct.
class Test {
constructor() {
this.var1 = 'var1'
}
method1() {
console.log(this.var1)
}
test() {
this.method2()
}
}
var mixin = {
var2: 'var2',
method2: {
console.log(this.var2)
}
}
If I run (new Test()).test(), it will fail because there's no method2 on the class, as it's in the mixin, that's why I need to add the mixin variables and methods to the class.
I see there's a lodash mixin function https://lodash.com/docs/4.17.4#mixin, but I don't know how I could use it with ES6 classes. I'm fine with using lodash for the solution, or even plain JS with no libraries to provide the mixin functionality.

Javascript's object/property system is much more dynamic than most languages, so it's very easy to add functionality to an object. As functions are first-class objects, they can be added to an object in exactly the same way. Object.assign is the way to add the properties of one object to another object. (Its behaviour is in many ways comparable to _.mixin.)
Classes in Javascript are only syntactic sugar that makes adding a constructor/prototype pair easy and clear. The functionality hasn't changed from pre-ES6 code.
You can add the property to the prototype:
Object.assign(Test.prototype, mixin);
You could add it in the constructor to every object created:
constructor() {
this.var1 = 'var1';
Object.assign(this, mixin);
}
You could add it in the constructor based on a condition:
constructor() {
this.var1 = 'var1';
if (someCondition) {
Object.assign(this, mixin);
}
}
Or you could assign it to an object after it is created:
let test = new Test();
Object.assign(test, mixin);

In es6 you can do this without assigning and you can even invoke the mixin constructor at the correct time!
http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/#bettermixinsthroughclassexpressions
This pattern uses class expressions to create a new base class for every mixin.
let MyMixin = (superclass) => class extends superclass {
foo() {
console.log('foo from MyMixin');
}
};
class MyClass extends MyMixin(MyBaseClass) {
/* ... */
}

You should probably look at Object.assign(). Gotta look something like this:
Object.assign(Test.prototype, mixin);
This will make sure all methods and properties from mixin will be copied into Test constructor's prototype object.

I'm surprised to find that none of the answers mentions what I would consider a mixin in the sense of composition (and in contrast to inheritance), which to me is a function that adds functionality to an object. Here's an example making use of both inheritance and composition:
class Pet { constructor(name) { this.name = name } }
class Cat extends Pet { expression = 'miaow' }
class Dog extends Pet { expression = 'bark' }
class Human { constructor(name, age) { this.name = name; this.age = age; } }
class American extends Human { expression = 'say howdy' }
function canSayHello(...contexts) {
for (const context of contexts) {
context.sayHello = function() {
console.log(`Hello my name is ${this.name} and I ${this.expression}`)
}
}
}
canSayHello(Pet.prototype, Human.prototype); // apply the mixin
const garfield = new Cat('garfield');
const pluto = new Dog('pluto');
const joebiden = new American('Joe Biden', 79);
garfield.sayHello();
pluto.sayHello();
joebiden.sayHello();

Related

Is it possible for a javascript class to define a method which fires if the class is called?

In python there's something like __call__ for this. Consider the following example:
class MyClass {
__call__() { return 'called!' }
}
const myType = new MyClass();
myType(); // called!
The question is what should I replace __call__ with?
I was doing some research, and most of the answers recommend __proto__, but it doesn't seem to work.
It is not possible out-of-the-box, but you can extend Function, and use the Function constructor to forward a call to __call__. If you have multiple classes that need this feature, extend Function only once into -- let's say -- a Callable class, and then inherit your other classes from that:
class Callable extends Function {
constructor() {
super("...args", "return this.__call__(...args)");
return this.bind(this);
}
}
class Class extends Callable {
__call__() { return 'called!' }
}
let inst = new Class();
console.log(inst());
Background
In JavaScript an object is callable when, and only if, it has the [[Call]] internal slot. But there is (currently) no way to give any given object this slot via JavaScript code. One must start with a function object and extend that.
Adding a constructor, inheritance
The above solution allows the constructor to define properties in the usual way: the constructed object is an instance of the class:
class Callable extends Function {
constructor() {
super("...args", "return this.__call__(...args)");
return this.bind(this);
}
}
class Class extends Callable {
constructor(data) {
super();
this.x = data;
}
__call__() { return 'called!' }
}
let inst = new Class(42);
console.log(inst instanceof Class); // true
console.log(inst.x); // 42
console.log(inst());
You can use constructor.
class Example {
constructor() {
// gets called on class initialization
}
}
Inside the constructor you can also call other methods if you want.
However this won't create an invoke function like using PHP's __invoke if that's what you meant. If that's what you're looking for then I don't know.

How to instantiate a Class from a String in JavaScript

I'm in a weird situation that i need to instantiate a new Class with a string stored in a variable but even i'm sure the class name is correct i get an error that given class name is not a constructor
Here is a dummy code that doesn't work:
class Foo {
constructor(){
console.log('Foo!');
}
};
const foo = 'Foo';
const bar = new window[foo]();
console.log(bar);
This trow this error:
Uncaught TypeError: window[foo] is not a constructor
One possibility is to use eval.
class Foo {
constructor() {
console.log('Foo!');
}
};
const foo = 'Foo';
const bar = eval(`new ${foo}()`);
console.log(bar);
You will have to evaluate the safety of using eval() in your particular circumstances. If you know the origin of the string you are inserting into the code that you run eval() on or you can sanitize it first, then it may be safe.
I personally would prefer a lookup table. If you have a known number of classes that you want to map by string, then you can make your own lookup table and use that. This has the advantage of there can be no unintended consequences if the string has weird stuff in it:
class Foo {
constructor() {
console.log('Foo!');
}
};
class Goo {
constructor() {
console.log('Goo!');
}
};
// construct dict object that contains our mapping between strings and classes
const dict = new Map([
['Foo', Foo],
['Goo', Goo]
]);
// make a class from a string
const foo = 'Foo';
let bar = new(dict.get(foo))()
console.log(bar);
If you were really going to go this route, you may want to encapsulate it in a function and then add error handling if the string is not found in the dict.
This should be better than using the global or Window object as your lookup mechanism for a couple reasons:
If I recall, class definitions in ES6 are not automatically put on the global object like they would with other top level variable declarations (Javascript trying to avoid adding more junk on top of prior design mistakes).
So, if you're going to manually assign to a lookup object, you might as well use a different object and not pollute the global object. That's what the dict object is used for here.
Similar to #jfriend00 ...
const className = "Foo";
const dynamicConstructor = {};
dynamicConstructor[className] = class {
constructor() {
console.log('Foo!');
}
};
const fooInstance = new dynamicConstructor[className]();
console.log(fooInstance);
A sort of factory class constructor can also be used
const classFactory = (_className) => {
let dynamicConstructor = {};
dynamicConstructor[_className] = class {
constructor(_code) {
this.code = _code;
console.log(`${_className} initialised with code: ${_code}!`);
}
};
return dynamicConstructor[_className];
}
const MyClass = classFactory("Foo");
let fooInstance2 = new MyClass(123);
console.debug(fooInstance2);
There are good solutions but I think we need a little bit more of theory
This questions is the best example to use a Factory Pattern
Design patterns can make your code more flexible, more resilient to change and easier to maintain.
Teo, is possible to use Factory Patterns in JavaScript?
Yes, my young Padawan.
But, what is the Factory pattern?
The factory pattern is a creational design pattern, which means it deals with object creation. There are three theoretical types of factory patterns:
Simple factory
Factory method
Abstract factory
Simple Factory is an object which encapsulates the creation of another object. In ES6 it could be a constructor being instantiated by new in a function and then return the instance like this:
class Player {...}
const PlayerFactory = {
makePlayer: (type, level) => new Player(type, level),
}
In this example makePlayer returns the instance of the Player class.
Factory Method defines one method for creating a class instance, which is overridden by subclasses who decide what to return.
In ES6 it could be implemented extending classes because there are no interfaces and using a method to instantiate and object using new
class Dragon {...}
class Snake {...}
class Player {
fightMonster() {
const monster = this.makeMonster()
monster.attack()
}
}
class Warrior extends Player {
makeMonster() {
return new Dragon()
}
}
class Knight extends Player {
makeMonster() {
return new Snake()
}
}
In this example, Player class call makeMonster method then Warrior and Knight classes override makeMoster method to return either a Dragon or a Snake class instance.
Finally, the Abstract Factory provides an interface for creating families of related or dependent objects without specifying their concrete classes
The interpretation of families could be like a category or list of classes. In ES6 it can be an instance that encapsulates a group of individual factories with a common goal. It separates the details of implementation of a set of objects from their general usage.
class WinButton {
constructor(options) {
this.name = 'WinButton'
this.options = options
}
}
class LinuxButton {
constructor(v) {
this.name = 'LinuxButton'
this.options = options
}
}
// Mapping names and class definitions
const supportedOS = new Map([
['Windows', WinButton],
['Linux', LinuxButton]
])
// Use a Factory Abstract pattern
const classFactory = (c, v) => {
const maker = supportedOS.get(c)
return new(maker)(v)
}
// Factory a class from a string
const name = 'Windows'
const param = {enabled: true}
const btn = classFactory(name, param)
console.log({btn})
In this final example we can see that the function classFactory uses the Factory Abstract pattern because instantiate a class from a list of supported OS (Linux or Windows) by setting maker with the constructor of the desired class, in this case WinButton class.

Create ES6/ESNext prototype function with different scope (not an inline function)

Ok say we have this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
printName() {
console.log('this.name');
}
}
what I want to do is define printName, something like this:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
// we want to define printName using a different scope
// this syntax is close, but is *not* quite correct
printName: makePrintName(foo, bar, baz)
}
where makePrintName is a functor, something like this:
exports.makePrintName = function(foo, bar, baz){
return function(){ ... }
};
is this possible with ES6? My editor and TypeScript is not liking this
NOTE: using ES5, this was easy to do, and looks like this:
var Car = function(){...};
Car.prototype.printName = makePrintName(foo, bar, baz);
Using class syntax, currently the best thing that is working for me, is this:
const printName = makePrintName(foo,bar,baz);
class Car {
constructor(){...}
printName(){
return printName.apply(this,arguments);
}
}
but that is not ideal. You will see the problem if you try to use class syntax to do what ES5 syntax can do. The ES6 class wrapper, is therefore a leaky abstraction.
To see the real-life use case, see:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L171
the problem with using TestBlock.prototype.startSuite = ..., is that in that case, I cannot simply return the class on line:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L67
The preferable ways to do this in JavaScript and TypeScript may differ due to limitations in typing system, but if printName is supposed to be a prototype method and not instance method (the former is beneficial for several reasons), there are not so many options.
Prototype method can be retrieved via accessor. In this case it should be preferably memoized or cached to a variable.
const cachedPrintName = makePrintName(foo, bar, baz);
class Car {
...
get printName(): () => void {
return cachedPrintName;
}
}
And it can be lazily evaluated:
let cachedPrintName;
class Car {
...
get printName(): () => void {
return cachedPrintName || cachedPrintName = makePrintName(foo, bar, baz);
}
}
Or it can be assigned to class prototype directly. In this case it should be additionally typed as class property because TypeScript ignores prototype assignments:
class Car {
...
printName(): () => void;
}
Car.prototype.printName = makePrintName(foo, bar, baz);
Where () => void is the type of a function that makePrintName returns.
A way that is natural to TypeScript is to not modify class prototypes but extend prototype chain and introduce new or modified methods via mixin classes. This introduces unnecessary complexity in JavaScript yet keeps TypeScript happy about types:
function makePrintNameMixin(foo, bar, baz){
return function (Class) {
return class extends Class {
printName() {...}
}
}
}
const Car = makePrintNameMixin(foo, bar, baz)(
class Car {
constructor() {...}
}
);
TypeScript decorator cannot be seamlessly used at this point because class mutation is not supported at this moment. The class should be additionally supplemented with interface to suppress type errors:
interface Car {
printName: () => void;
}
#makePrintNameMixin(foo, bar, baz)
class Car {
constructor() {...}
}
Just replace : with =
printName = makePrintName()
: goes for type notation.
Edit
As noted in comments the above will not change the prototype. Instead, you can do this outside the class definition, using ES5 syntax:
// workaround: extracting function return type
const dummyPrintName = !true && makePrintName();
type PrintNameType = typeof dummyPrintName;
class Car {
// ...
printName: PrintNameType;
}
Car.prototype.printName = makePrintName();
Playground
Another idea I haven't seen mentioned yet is to use a method decorator. The following decorator takes a method implementation and puts it on the prototype, as desired:
function setMethod<T extends Function>(value: T) {
return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {
descriptor.value = value;
delete descriptor.get;
delete descriptor.set;
};
}
Put it in a library somewhere. Here's how you'd use it:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
#setMethod(makePrintName(foo, bar, baz))
printName() {} // dummy implementation
}
The only downside is that you have to put a dummy implementation of the method with the right signature in the class, since the decorator needs something to decorate. But it behaves exactly as you want at runtime (it isn't an instance method which costs a new function definition for each instance, or an accessor which costs an extra function call at each use).
Does that help?
Why don't you try something like this
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
this.printName = makePrintName(foo, bar, baz);
}
}
am I dont getting it or ..??
class keyword normally is just a syntax sugar of the delegate prototype in ES5. I just tried it in typescript
class Car {
private kind: string;
private name : string;
printName :Function;
constructor(name) {
this.kind = 'Car';
this.name = name;
}
}
var makePrintName = function (foo, bar, baz) {
return function () { console.log(foo, bar, baz); };
};
Car.prototype.printName = makePrintName('hello', 'world', 'did you get me');
var bmw = new Car('bmw');
bmw.printName();
console.log(bmw.hasOwnProperty('printName'));

Class variable using Class syntax in Javascript [duplicate]

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?
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
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.
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'
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
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.
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.
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).
[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);
}
}
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);
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
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
}
}
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.
Just define a getter.
class MyClass
{
get MY_CONST () { return 'string'; }
constructor ()
{
console.log ("MyClass MY_CONST:", this.MY_CONST);
}
}
var obj = new MyClass();
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.
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()
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);
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)...

How to inherit static methods from base class in JavaScript?

I'm trying to achieve some basic OOP in JavaScript with the prototype way of inheritance. However, I find no way to inherit static members (methods) from the base class.
We can simulate the basic class model by using prototype:
SomeClass = function(){
var private_members;
this.public_method = function(){
//some instance stuff..
};
};
Class.static_method = function(){
//some static stuff;
};
//Inheritance
SubClass = function(){ //sub-class definition };
SubClass.prototype = new Class();
However, SubClass doesn't inherit static_method from Class.
In the classical (OO) inheritance pattern, the static methods do not actually get inherited down. Therefore if you have a static method, why not just call: SuperClass.static_method() whenever you need it, no need for JavaScript to keep extra references or copies of the same method.
You can also read this JavaScript Override Patterns to get a better understanding of how to implement inheritance in JavaScript.
For ES5 you will need to use Object.assign to copy static methods from BaseClass to SubClass but for ES6 it should work without using Object.assign
ES5 Example
var BaseClass = function(){
}
BaseClass.sayHi = function(){
console.log("Hi!");
}
var SubClass = function(){
}
Object.assign(SubClass , BaseClass);
BaseClass.sayHi(); //Hi
SubClass.sayHi(); //Hi
ES6 Example
class BaseClass {
static sayHi(){
console.log("Hi!");
}
}
class SubClass extends BaseClass{
}
BaseClass.sayHi() //Hi
SubClass.sayHi() //Hi
After your example code you can do this:
for (var i in Class) {
SomeClass[i] = Class[i];
}
to copy static members from Class to SubClass.
If you're using jQuery, have a look at the jQuery.Class plugin from JavaScriptMVC. Or you can extend John Resig's Simple JavaScript Inheritance for a more library-agnostic system.
Try this:
class BaseClass {
static baseMethod () {
console.log("Hello from baseMethod");
}
}
class MyClass extends BaseClass {
constructor(props) {
super(props);
}
}
Object.assign(MyClass, BaseClass);
They key is Object.assign which should be everyone's new best friend. You can now call any base method from BaseClass using MyClass as follows:
MyClass.baseMethod();
You can see this live and in action on this pen.
Enjoy!
How are you implementing 'static' methods? Since JavaScript doesn't have a native class/instance object model, it all depends on how you've designed your own class system.
If you want to be able to inherit anything it'll have to be using the SomeClass.prototype object, rather than putting anything directly on the SomeClass constructor function. So essentially you'll be defining static methods as normal instance methods, but ones that don't care about what value of this is passed into them.
you can access static fields via this.constructor[staticField];
class A {
static get Foo() { return 'Foo'; }
constructor() {
console.log(`Class ${this.constructor.name}`, this.constructor.Foo);
}
}
class B extends A {
static get Foo() { return 'Baz'; }
}
class C extends A {}
const a = new A();
const b = new B();
const c = new C()

Categories