While trying to find a way to use nested classes in JS, I came up with this sort of thing:
class Character {
constructor() {
this.Info= class I {
constructor(name,value) {
this.name=name;
this.value=value;
}
};
}
bar () {
var trial = new this.Info("Goofy", 2);
alert(trial.name);
}
}
var test = new Character();
test.bar();
and it seems to work. However, I'm afraid this might be creating a new function object for each new call, as I define the class in the constructor (which is executed at each new call). Is there a more efficient way of doing this?
This question does not solve my issue as the author only wonders how to even have a nested class; I'm already able to do that but I wonder if there's a more efficient way.
Using a static property in react, angular or just using babel, because direct static class properties are not currently implemented on all browsers.
class Character {
static Info = class I {
constructor(name) { this.name=name; }
}
bar () {
return new Character.Info("Goofy");
}
}
const test = new Character();
console.log(test.bar());
Using a static property the old way -- currently working on all browsers.
class Character {
bar () { return new Character.Info("Goofy"); }
}
Character.Info = class I {
constructor(name) { this.name=name; }
}
const test = new Character();
console.log(test.bar());
Maybe the example you've given is too simple to demonstrate whatever problem you're trying to solve, but it seems to me you don't need to nest them at all.
class Info {
constructor(name, value) {
this.name = name;
this.value = value;
}
}
class Character {
bar() {
var trial = new Info("Goofy", 2);
console.log(trial.name);
}
}
const test = new Character();
test.bar();
I think in javascript it could create Singleton class like below
test.js
class Container {
constructor() {
this.map = new Map;
}
set(key, value) {
this.map.set(key, value);
}
get(key) {
return this.map.get(key);
}
}
module.exports.Container = new Container();
so that
I could use that other files like in index.js
import container from './test'
However the constructor of Container need some other parameters so that it could do better. And the Container also need to be Singleton class ,
because it is a common class . And i do not know how to create it?
constructor(servie) {
this.map = new Map;
this.servie = servie;
}
by the way the service variable is created when application starts
EDIT: I've realised my naming is slightly confusing, as I've used Container to represent the IoC container, and then realised you've used that name to represent your Singleton.
Providing you are able to instantiate your singleton at a central point of code (entry point file for example, while setting up server). You can achieve a Singleton in a number of ways. For example:
let instance = null;
class Singleton {
constructor(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
}
module.exports = (...args) => {
return instance || (instance = new Singleton(...args));
}
You could do this any multitude of ways e.g. with static functions instead of the anonymous function. However, with all of these I think it becomes slightly confused as to whether you're init'ing the instance or just trying to retrieve it.
IoC container patterns (often used in C# projects) are a little cleaner in my opinion. Where you might have a single container class that keeps track of your singletons and provides separate access and initiation functions.
class Container {
constructor() {
this.instances = {};
}
add(name, instance) {
this.instances[name] = instance; // depends if you want overwrite or not
}
get(name) {
if (!this.instances[name]) {
throw new Error('some appropriate error messaging for your app');
}
return this.instances[name];
}
remove(name) {
delete this.instances[name];
}
}
module.exports = new Container(); // this has to be a no-param constructor
Then in your app init code, you initialise the singletons and register them with your container:
const Container = require('<path_to_Container>');
const Singleton = require('<path_to_Singleton>');
...
Container.add('mySingleton', new Singleton(arg1, arg2));
and access it at any time with:
Container.get('mySingleton');
Couple notes:
You could use Singleton.name instead of a string name ('mySingleton' in the example)
This is just a personal preference. But I like it because it feels more declarative, you register (add) an instance to the container at app start-up and don't blur the lines between initialisation and usage. And it means that if you add more of these singletons going forward, you have a single pattern for it already in place.
I am trying to come up with a generic builder function for a large hierarchy of objects in Javascript. The goal is to implement as much functionality as possible at the top of the hierarchy. After playing around for a little while, I have ended up with a structure I like, although am not completely happy with.
The structure currently looks somewhat like this. I have attached a working (simplified) version below:
class AbstractItem {
constructor(build) {
if (this.constructor === AbstractItem) {
throw new TypeError("Oops! AbstractItem should not be instantiated!");
}
this._id = build.id;
}
/*
The generic ItemBuilder is part of an abstract superclass.
Every item should have an ID, thus the builder validates this.
It also provides a generic build() function, so it does not have to be re-implemented by every subclass.
*/
static get Builder() {
/*
This constant references the constructor of the class for which the Builder function was called.
So, if it was called for ConcreteItem, it will reference the constructor of ConcreteItem.
This allows us to define a generic build() function.
*/
const BuildTarget = this;
class ItemBuilder {
constructor(id) {
if (!id) {
throw new TypeError('An item should always have an id!');
}
this._id = id;
}
//The generic build method calls the constructor function stored in the BuildTarget variable and passes the builder to it.
build() {
return new BuildTarget(this);
}
get id() {
return this._id;
}
}
return ItemBuilder;
}
doSomething() {
throw new TypeError("Oops! doSomething() has not been implemented!");
}
get id() {
return this._id;
}
}
class AbstractSubItem extends AbstractItem {
constructor(build) {
super(build);
if (this.constructor === AbstractSubItem) {
throw new TypeError("Oops! AbstractSubItem should not be instantiated!");
}
this._name = build.name;
}
/*
AbstractSubItem implements a different version of the Builder that also requires a name parameter.
*/
static get Builder() {
/*
This builder inherits from the builder used by AbstractItem by calling the Builder getter function and thus retrieving the constructor.
*/
class SubItemBuilder extends super.Builder {
constructor(id, name) {
super(id);
if (!name) {
throw new TypeError('A subitem should always have a name!');
}
this._name = name;
}
get name() {
return this._name;
}
}
return SubItemBuilder;
}
get name() {
return this._name;
}
}
class ConcreteItem extends AbstractItem {
doSomething() {
console.log('Hello world! My name is ' + this.id + '.');
}
}
class ConcreteSubItem extends AbstractSubItem {
doSomething() {
console.log('Hello world! My name is ' + this.name + ' (id: ' + this.id + ').');
}
}
new ConcreteItem.Builder(1).build().doSomething();
new ConcreteSubItem.Builder(1, 'John').build().doSomething();
In my opinion, there are some pros and cons to my current approach.
Pros
The Builder() method provides a common interface that can be used to obtain a builder for all implementing classes.
My concrete classes can inherit the builder class without any additional effort.
Using inheritance, the builder can be easily expanded if needed.
The builder code is part of the abstract class, so it is clear what is being built when reading the code.
The calling code is easy to read.
Cons
It is not clear, looking at the Builder() getter function, which parameters are required to avoid an exception. The only way to know this is to look at the constructor (or at the comments), which is buried a couple of layers deep.
It feels counter-intuitive having the SubItemBuilder inherit from super.Builder, rather than a top-level class. Likewise, it may not be clear to other how to inherit from the ItemBuilder without looking at the SubItemBuilder example.
It is not really clear, looking at the AbstractItem class, that it should be constructed using the builder.
Is there a way to improve my code to negate some of the cons I've mentioned? Any feedback would be very much appreciated.
I have a Javascript class (in ES6) that is getting quite long. To organize it better I'd like to split it over 2 or 3 different files. How can I do that?
Currently it looks like this in a single file:
class foo extends bar {
constructor(a, b) {} // Put in file 1
methodA(a, b) {} // Put in file 1
methodB(a, b) {} // Put in file 2
methodC(a, b) {} // Put in file 2
}
Thanks!
When you create a class
class Foo extends Bar {
constructor(a, b) {
}
}
you can later add methods to this class by assigning to its prototype:
// methodA(a, b) in class Foo
Foo.prototype.methodA = function(a, b) {
// do whatever...
}
You can also add static methods similarly by assigning directly to the class:
// static staticMethod(a, b) in class Foo
Foo.staticMethod = function(a, b) {
// do whatever...
}
You can put these functions in different files, as long as they run after the class has been declared.
However, the constructor must always be part of the class declaration (you cannot move that to another file). Also, you need to make sure that the files where the class methods are defined are run before they are used.
Here's my solution. It:
uses regular modern classes and .bind()ing, no prototype. (EDIT: Actually, see the comments for more on this, it may not be desirable.)
works with modules. (I'll show an alternative option if you don't use modules.)
supports easy conversion from existing code.
yields no concern for function order (if you do it right).
yields easy to read code.
is low maintenance.
unfortunately does not play well with static functions in the same class, you'll need to split those off.
First, place this in a globals file or as the first <script> tag etc.:
BindToClass(functionsObject, thisClass) {
for (let [ functionKey, functionValue ] of Object.entries(functionsObject)) {
thisClass[functionKey] = functionValue.bind(thisClass);
}
}
This loops through an object and assigns and binds each function, in that object, by its name, to the class. It .bind()'s it for the this context, so it's like it was in the class to begin with.
Then extract your function(s) from your class into a separate file like:
//Use this if you're using NodeJS/Webpack. If you're using regular modules,
//use `export` or `export default` instead of `module.exports`.
//If you're not using modules at all, you'll need to map this to some global
//variable or singleton class/object.
module.exports = {
myFunction: function() {
//...
},
myOtherFunction: function() {
//...
}
};
Finally, require the separate file and call BindToClass like this in the constructor() {} function of the class, before any other code that might rely upon these split off functions:
//If not using modules, use your global variable or singleton class/object instead.
let splitFunctions = require('./SplitFunctions');
class MySplitClass {
constructor() {
BindToClass(splitFunctions, this);
}
}
Then the rest of your code remains the same as it would if those functions were in the class to begin with:
let msc = new MySplitClass();
msc.myFunction();
msc.myOtherFunction();
Likewise, since nothing happens until the functions are actually called, as long as BindToClass() is called first, there's no need to worry about function order. Each function, inside and outside of the class file, can still access any property or function within the class, as usual.
I choose to have all privte variables/functions in an object called private, and pass it as the first argument to the external functions.
this way they have access to the local variables/functions.
note that they have implicit access to 'this' as well
file: person.js
const { PersonGetAge, PersonSetAge } = require('./person_age_functions.js');
exports.Person = function () {
// use privates to store all private variables and functions
let privates={ }
// delegate getAge to PersonGetAge in an external file
// pass this,privates,args
this.getAge=function(...args) {
return PersonGetAge.apply(this,[privates].concat(args));
}
// delegate setAge to PersonSetAge in an external file
// pass this,privates,args
this.setAge=function(...args) {
return PersonSetAge.apply(this,[privates].concat(args));
}
}
file: person_age_functions.js
exports.PersonGetAge =function(privates)
{
// note: can use 'this' if requires
return privates.age;
}
exports.PersonSetAge =function(privates,age)
{
// note: can use 'this' if requires
privates.age=age;
}
file: main.js
const { Person } = require('./person.js');
let me = new Person();
me.setAge(17);
console.log(`I'm ${me.getAge()} years old`);
output:
I'm 17 years old
note that in order not to duplicate code on person.js, one can assign all functions in a loop.
e.g.
person.js option 2
const { PersonGetAge, PersonSetAge } = require('./person_age_functions.js');
exports.Person = function () {
// use privates to store all private variables and functions
let privates={ }
{
// assign all external functions
let funcMappings={
getAge:PersonGetAge,
setAge:PersonSetAge
};
for (const local of Object.keys(funcMappings))
{
this[local]=function(...args) {
return funcMappings[local].apply(this,[privates].concat(args));
}
}
}
}
You can add mixins to YourClass like this:
class YourClass {
ownProp = 'prop'
}
class Extension {
extendedMethod() {
return `extended ${this.ownProp}`
}
}
addMixins(YourClass, Extension /*, Extension2, Extension3 */)
console.log('Extended method:', (new YourClass()).extendedMethod())
function addMixins() {
var cls, mixin, arg
cls = arguments[0].prototype
for(arg = 1; arg < arguments.length; ++ arg) {
mixin = arguments[arg].prototype
Object.getOwnPropertyNames(mixin).forEach(prop => {
if (prop == 'constructor') return
if (Object.getOwnPropertyNames(cls).includes(prop))
throw(`Class ${cls.constructor.name} already has field ${prop}, can't mixin ${mixin.constructor.name}`)
cls[prop] = mixin[prop]
})
}
}
TypeScript Solution
foo-methods.ts
import { MyClass } from './class.js'
export function foo(this: MyClass) {
return 'foo'
}
bar-methods.ts
import { MyClass } from './class.js'
export function bar(this: MyClass) {
return 'bar'
}
class.ts
import * as barMethods from './bar-methods.js'
import * as fooMethods from './foo-methods.js'
const myClassMethods = { ...barMethods, ...fooMethods }
class _MyClass {
baz: string
constructor(baz: string) {
this.baz = baz
Object.assign(this, myClassMethods);
}
}
export type MyClass = InstanceType<typeof _MyClass> &
typeof myClassMethods;
export const MyClass = _MyClass as unknown as {
new (
...args: ConstructorParameters<typeof _MyClass>
): MyClass;
};
My solution is similar to the one by Erez (declare methods in files and then assign methods to this in the constructor), but
it uses class syntax instead of declaring constructor as a function
no option for truly private fields - but this was not a concern for this question anyway
it does not have the layer with the .apply() call - functions are inserted into the instance directly
one method per file: this is what works for me, but the solution can be modified
results in more concise class declaration
1. Assign methods in constructor
C.js
class C {
constructor() {
this.x = 1;
this.addToX = require('./addToX');
this.incX = require('./incX');
}
}
addToX.js
function addToX(val) {
this.x += val;
return this.x;
}
module.exports = addToX;
incX.js
function incX() {
return this.addToX(1);
}
module.exports = incX;
2. Same, but with instance fields syntax
Note that this syntax is a Stage 3 proposal as of now.
But it works in Node.js 14 - the platform I care about.
C.js
class C {
x = 1;
addToX = require('./addToX');
incX = require('./incX');
}
Test
const c = new C();
console.log('c.incX()', c.incX());
console.log('c.incX()', c.incX());
I'm using the MooTools class system, and I'd like to be able to access any static member of a particular class without having to know the full inheritance chain. For example, if I have a ChildClass that extends BaseClass, and
BaseClass.foo = function() { /*...*/ }
I'd like to be able to call ChildClass.foo().
To this end, I'm thinking of modifying the MooTools Class method as follows:
function Class(params)
// ...
// var newClass = ...
var parentClass = params.Extends;
if (parentClass) {
newClass.__proto__ = parentClass;
}
// ...
}
This will set up each class object's prototype chain to point to its parent class.
If a static member from a higher class is hidden in a more derived class, so be it.
Notwithstanding the use of the deprecated __proto__, am I on the right track here? Does anyone see any glaring problems?
You can always extend the Extend Mutator:
(function(){
var original = Class.Mutators.Extends;
Class.Mutators.Extends = function(parent) {
original.call(this, parent);
var members = {};
for (var key in parent) {
if (parent.hasOwnProperty(key) && !this.hasOwnProperty(key)) {
members[key] = parent[key];
}
}
this.extend(members);
};
}());
You should check out Mark Obcena's book.