Nodejs: Don't run `new class` with export - javascript

this is my config:
const one = new one()
const two = new two()
export default {
one,
two
}
And this is my classes:
export class one {
constructor () {
console.log("one");
}
}
export class two {
constructor () {
console.log("two");
}
}
And this is my setup:
import runner from "./";
runner.one
Why after call runner.one, also runner.two running?!
I want to run only runner.one

It happens in here:
const one = new one()
const two = new two()
cause You defined in constructor() methods of both classes to do console.log
when You call new ClassNameHere() it executes constructor()
You could simply export classes instead of instantiating them:
runners.mjs
export class one {
constructor () {
console.log("one");
}
}
export class two {
constructor () {
console.log("two");
}
}
executor.mjs
import * as runners from "./runners";
const one = new runner.one();
OR name classes CapitalizedCamelCased:
runners.mjs
export class RunnerOne {
constructor () {
console.log("one");
}
}
export class RunnerTwo {
constructor () {
console.log("two");
}
}
executor.mjs
import {RunnerOne} from "./runners";
const one = new RunnerOne();

It's happing because you're instantiating both of them globally using const specifier.
When you do this, the code calls the constructor of each class as soon as it comes across instantiation (new keyword).
const one = new one()
const two = new two()
export default {
one,
two
}
If this is not what you want, and you want them to initialize separately, there could be multiple ways to achieve that.
One is to separately instantiate them, before you access them. (You could use it in a situation where you still need access to instantiated object inside the class you're instantiating them in). Something like this:
Class that contains one and two:
(assuming you define your classes in file onetwo.mjs)
import * as ot from "./onetwo.mjs";
let one;
let two;
function instantiateOne() {
one = new ot.one();
}
function instantiateTwo() {
two = new ot.two();
}
export default {
one,
two,
instantiateOne, // expose methods needed to create instances
instantiateTwo,
}
Class that uses above:
import runner from "./";
runner.instantiateOne(); // this will only create instance of 'one'
runner.one; // accessing one
Of course there are other ways, and it might need more changes to make it work in your project, but this is one of the patterns. Just be aware when using such a strategy, you either always check before using the object (one or two) that they have been instantiated, or you ensure you do it at start.
NOTE: This is just to give you an idea. This isn't a concrete implementation. If you do want to implement something like this, you'll have to handle all edge cases (example, prevent re-initialization etc.)

Related

javascript good way to create or design Singleton class

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.

Should I use ES6 Class' static methods when defining a component?

If I have a simple component such as the one below, would it better to use static methods within my class or not? I realise this could be down to opinion but what I'm interested in is if there are architectural reasons why one way might have advantages over the other.
Non static methods:
class mainNav {
toggleMainNav() {
const navBtn = document.getElementById('toggle-menu');
const navMenu = document.getElementById('main-nav');
navBtn.addEventListener('click', () => {
navMenu.classList.toggle('open');
});
}
init() {
this.toggleMainNav();
}
}
module.exports = mainNav;
To instantiate I would need to instantiate the class first like so:
const mainNav = require("../js/components/mainNav/mainNav");
//Init nav
const nav = new mainNav;
nav.init();
Alternatively with static methods I could do this:
class mainNav {
static toggleMainNav() {
const navBtn = document.getElementById('toggle-menu');
const navMenu = document.getElementById('main-nav');
navBtn.addEventListener('click', () => {
navMenu.classList.toggle('open');
});
}
static init() {
this.toggleMainNav();
}
}
module.exports = mainNav;
and instantiate:
const mainNav = require("../js/components/mainNav/mainNav");
mainNav.init();
On the face of it using static methods in this case seems easier as I don't have to instantiate an instance of the class first.
Not coming from an OOP programming background, Is there is a reason why doing this would be considered bad practise?
A class with no data is basically a collection of static methods. This is an antipattern. In this case, just exporting the function alone would suffice, like this:
function doSomething() { ... }
module.exports = doSomething
and use it like this:
const func = require('../path/module')
func()

Node.js: exporting class/prototype vs. instance

As I do most of my programming in Java, I find it compelling to export a class in a Node.js module instead of an object instance, e.g.:
class Connection {
constructor(db) {
this.db = db;
}
connect(connectionString) {
this.db.connect(connectionString);
}
}
exports.Connection = Connection;
Since doing this would require instantiating the class multiple times across dependent modules, I still need to export an already existing instance for use in the rest of the production code. I do it in the same module:
exports.connection = new Connection(require("mongoose"));
This allows for some testability, as the real dependency can be swapped in a test:
const Connection = require("./connection").Connection;
describe("Connection", () => {
it("connects to a db", () => {
const connection = new Connection({connect: () => {}});
// ...
});
});
This approach works, but it has a strange feel to it as I'm mixing two patterns here: exporting a prototype (for unit tests) and an instance (for the production code). Is this acceptable? Should I continue with this or change to something different? If so, what is the preferred pattern?
You're right, it's a bad coding style, but actually you can write a function which, depending on the received parameter, returns either the single instance (for the whole application), or the class itself (for testing). Something like this:
class MyClass() {}
const instance = new MyClass();
function getInstanceOrClass(isTesting) {
if(isTesting) {
return MyClass;
} else {
return instance;
}
}
exports.getInstanceOrClass = getInstanceOrClass;
// in other files
const getInstanceOrClass = require('./yourFileName');
const classSingletonInstance = getInstanceOrClass();
// in test files
const getInstanceOrClass = require('./yourFileName');
const MyClass = getInstanceOrClass(true);

Split a Javascript class (ES6) over multiple files?

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());

How to access a method from a class from another class?

I want to use Object Oriented Programming technique with JavaScript but I can't access a method from one class from another class. How can do like the following?
class one{
write(){
console.log("Yes! I did!");
}
}
class two{
var object=new one();
tryingMethod(){
object.write();
}
}
I get the following error:
Uncaught SyntaxError: Unexpected identifier -->> for var object=new one();
Your syntax is not legal. There should be an error in your console showing you which line of code is not correct.
If it's a static method (doesn't use any instance data), then declare it as a static method and you can directly call it.
If it's an instance method, then you would typically create an object of type one and then call the method on that object (usually in the constructor).
To make the method static (which appears to be fine in your specific case):
class One {
static write(){
console.log("Yes! I did!");
}
}
class Two {
tryingMethod(){
One.write();
}
}
For the non-static case, you don't have the proper syntax. It appears you want to create the instance of the One object in a constructor for Two like this:
class One {
write(){
console.log("Yes! I did!");
}
}
class Two {
constructor() {
this.one = new One();
}
tryingMethod(){
this.one.write();
}
}
var x = new Two();
x.tryingMethod();
Note: I'm also following a common Javascript convention of using an identifier that starts with a capital letter for the class/constructor name such as One instead of one.
What I'd recommend doing is not tying the classes together so tightly and doing something like this...
class One {
write() {
console.log("Yes! I did!");
}
}
class Two {
constructor(one = new One()) {
this.one = one;
}
tryingMethod() {
this.one.write();
}
}
Now what you can do is...
const two = new Two();
two.write();
This allows you to have a better separation of concerns and allows you to more easily unit test the Two class because you can pass in a mock implementation of the One class if you want.
describe("two class", () => {
it("should do something", () => {
const one = {
write: sinon.spy()
};
const two = new Two(one)
two.tryingMethod();
expect(one.write.calledOnce).to.be.ok;
});
});
You can pack dependencies in a container.
class Provider {
private _one?: One;
private _two?: Two;
one(): One {
return this._one || (this._one = new One(this));
}
two(): Two {
return this._two || (this._two = new Two(this));
}
}
class One {
constructor(private provider: Provider) { }
write() {
console.log("Yes! I did!");
}
}
class Two {
constructor(private provider: Provider) { }
tryingMethod() {
this.provider.one().write();
}
}

Categories

Resources