Error when delegating class method in ES6 - javascript

I have this UseCase class:
class UseCase {
constructor(repository) {
this.repository = repository;
}
execute() {
//do stuff
}
}
module.exports = UseCase;
and this Service class:
class Service {
constructor(repository) {
this.useCase = new UseCase(repository);
}
doWork = this.useCase.execute;
}
module.exports = Service;
What I want is delegate service.doWork() call to useCase.execute(), but when I execute it, I get this error:
TypeError: Cannot read property 'execute' of undefined
However, if I change my Service code to this:
class Service {
constructor(repository) {
this.repository = repository;
}
doWork = new UseCase(this.repository).execute;
}
module.exports = Service;
it works properly! Why is that? What am I missing?

Class fields run as soon after the constructor they can, right after any super calls, if any. Your code is equivalent to:
class Service {
constructor(repository) {
this.doWork = this.useCase.execute;
this.useCase = new UseCase(repository);
}
}
It's not defined in time.
Put doWork in the constructor instead, after the assignment to useCase.
You also need to make sure that .execute is called with the proper calling context - just passing this.useCase.execute loses the calling context of useCase.
class Service {
constructor(repository) {
this.useCase = new UseCase(repository);
this.doWork = () => this.useCase.execute();
}
}
You could also use a class field which calls .execute when called:
class Service {
constructor(repository) {
this.useCase = new UseCase(repository);
}
doWork = () => this.useCase.execute();
}

Related

Dependency injection and method restriction

I have a class that manages a WebSocket connection and provides the methods to subscribe to this WebSocket. An instance of this class may be passed to many child objects that subscribe to this WebSocket via these methods:
const client = new WebSocketManager();
await client.connect();
const objA = new ClassA(client);
const objB = new ClassB(client);
client.close(); // at a future point in time
The problem is that client exposes critical methods like connect and close. If objA calls close, objB would fail for no apparent reason. Those two methods should be private to the children, but public to the initiator of the parent object. Is there a pattern to solve this problem? Two methods are presented below. Are any of those two patterns acceptable or are there better solutions? I would like to hear your opinion.
Method 1: Define an owner of the parent object. Restricted methods require a reference to the owner.
class Parent {
#owner;
constructor(owner) {
this.#owner = owner;
}
restricedMethod(owner) {
if(owner !== this.#owner)
throw Error('not authorized');
console.log('restricedMethod called');
}
accessibleMethod() {
console.log('accessibleMethod called');
}
}
class Child {
constructor(dependency) {
this.dependency = dependency;
}
callAccessibleMethod() {
this.dependency.accessibleMethod();
}
callRestricedMethod() {
this.dependency.restricedMethod();
}
}
const parent = new Parent(this);
// 'this' is the owner of 'parent'
const child = new Child(parent);
child.callAccessibleMethod();
// accessibleMethod called
try { child.callRestricedMethod(); } catch(e) { console.log(e.message); }
// Error: not autherized
parent.restricedMethod(this); // only the owner can call this method
// restricedMethod called
Method 2: Create a new parent object on the fly that only contains the methods that the child may access.
class Parent {
restricedMethod(){
console.log('restricedMethod called');
}
accessibleMethod(){
console.log('accessibleMethod called');
}
}
class Child {
constructor(dependency) {
this.dependency = dependency;
}
callAccessibleMethod() {
this.dependency.accessibleMethod();
}
callRestricedMethod() {
this.dependency.restricedMethod();
}
}
class MethodSelection {
constructor(object, methods) {
for (const method of methods)
this[method] = object[method];
}
}
const parent = new Parent();
// select methods from parent object and create new object
const restricted = new MethodSelection(parent, ['accessibleMethod']);
console.log(restricted.accessibleMethod === parent.accessibleMethod);
// true
const child = new Child(restricted);
child.callAccessibleMethod();
// accessibleMethod called
try { child.callRestricedMethod(); } catch(e) { console.log(e.message); }
// TypeError: this.dependency.restricedMethod is not a function
parent.restricedMethod();
// restricedMethod called

Implementing kind of a delegation pattern in Javascript

I have two classes, A and B. What I am trying to do is to pass data from A to B after receiving a message from sockets.
This is simplified look of how classes are defined:
class A:
export default class A {
client;
callbacks;
constructor() {
this.callbacks = {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: (data) => {this.client.logger.log(data)}, //I want to pass this data object to class B
};
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
this.client.userData(listenKey, this.callbacks);
}
}
I already have a property of A in class definition of B:
export default class B {
account;
constructor() {
this.account = new A();
}
}
What would be a correct/standard way to connect these two so I get a 'data' object from class A every time the socket message callback from class A is triggered?
I am a bit new with JS, but on iOS we would use a delegation pattern, with a protocol, that says:
class A will have a delegate property.
A delegate (class B) must implement a protocol (in this case it would be a requirement to implement method called didReceiveMessage(data).
After that, when a message is received in class A, we would just do(in socket message callback shown above) something like this.delegate.didReceiveMessage(data).
Protocol usage here is not important generally, but it is a plus, cause from A class, we can only access didReceiveData(data) method trough a delegate property, and nothing else (other properties / methods of class B are not visible). At least that is how it works in Swift/Obj-C. I just mentioned it, cause I am curious is this how it is done in JS too.
I guess there is some similar mechanism in Javascript, or some more standard/better way to achieve this kind of data sending between objects?
on iOS we would use a delegation pattern, with a protocol
You can do it exactly as you described:
export default class A {
client;
delegate;
constructor(delegate) {
this.delegate = delegate;
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
const callbacks = {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: (data) => this.delegate.didReceiveMessage(data),
};
this.client.userData(listenKey, callbacks);
}
}
export default class B {
account;
constructor() {
this.account = new A(this);
}
didReceiveMessage(data) {
console.log(data); // or whatever
}
}
There is no interface (protocol) declaration that would tell A which properties and methods it may access on the passed delegate, but the contract exists of course. You should document it in prose. (Or use TypeScript).
Notice also how your class A interacts with the Spot client, it uses very much the same pattern of passing an object with event handler methods.
A simpler pattern in JavaScript, if you just need a single method in your protocol, is to pass a callable function only:
export default class A {
client;
constructor(onMessage) {
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
this.client.userData(listenKey, {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: onMessage,
});
}
}
export default class B {
account;
constructor() {
this.account = new A(this.didReceiveMessage.bind(this));
// or inline:
this.account = new A(data => {
console.log(data); // or whatever
});
}
didReceiveMessage(data) {
console.log(data); // or whatever
}
}
I am not an expert on NodeJs, but you can use something like an emitter plugin.
In javascript, it would look like this:
function A() {
Emitter(this);
this.action = function() {
console.log("something happened");
this.emit("action", { prop: "value" });
};
}
function B(a_instance) {
// subscribe to "action" event
a.on("action", function(data) {
console.log(data.prop); // "value"
});
};
var myA = new A();
var myB = new B(myA);
myA.action();

Creating TypeScript class decorator for log correlation

I'm trying to create a TypeScript decorator that can be added to any class, that will create a request-scoped context that I can use to store a request ID. I've come across a couple of articles around decorators but none seem to fit my use-case.
Below is the code that I use to create the async hook, the decorator and a sample class that should be wrapped. When running the code, the actual response I receive is an empty object. The context is being lost but I'm not following why. I'm not receiving any errors or warnings.
Any suggestions would be highly appreciated.
This is the code I'm using to create the context. Calling the initContext() and getContext() functions.
import * as asyncHooks from 'async_hooks'
const contexts: any = {}
asyncHooks.createHook({
init: (asyncId: any, type: any, triggerAsyncId: any) => {
if (contexts[triggerAsyncId]) {
contexts[asyncId] = contexts[triggerAsyncId]
}
}
}).enable()
function initContext(fn: any) {
const asyncResource = new asyncHooks.AsyncResource('REQUEST_CONTEXT')
return asyncResource.runInAsyncScope(() => {
const asyncId = asyncHooks.executionAsyncId()
contexts[asyncId] = {}
return fn(contexts[asyncId])
})
}
function getContext() {
const asyncId = asyncHooks.executionAsyncId()
return contexts[asyncId] || {}
}
export { initContext, getContext }
This is the decorator that I'm using to wrap the class with. I'm trying to create the constructor within the context of the initContext function, set the context ID and then return the new constructor.
import { initContext } from './lib/context'
function AsyncHooksContext<T extends { new(...args: any[]): {} }>(target: T) {
return initContext((context: any) => {
context.id = 'some-uuid-goes-here'
return class extends target {
constructor(...args: any[]) {
super(...args)
}
}
})
}
export { AsyncHooksContext }
This is a sample class that should be able to produce the context ID
#AsyncHooksContext
class Foo {
public bar() {
const context = getContext()
console.log('This should be the context => ', { context })
}
}
new Foo().bar()

Run chained method before anything in constructor?

I have this simple class:
class Foo {
constructor() {
this.init();
return this;
}
init() {
this.onInit();
}
onInit(callback) {
this.onInit = () => callback();
return this;
}
}
new Foo().onInit(() => console.log('baz'));
It's obviously flawed, because it will call init before the onInit method is able to define the onInit property/callback.
How can I make this work without change the interface?
How can I make this work without change the interface?
You can't, the interface is inherently flawed. That's really the answer to your question.
Continuing, though, with "what can I do instead":
If you need to have a callback called during initialization, you need to pass it to the constructor, not separately to the onInit method.
class Foo {
constructor(callback) {
this.onInit = () => {
callback(); // Call the callback
return this; // Chaining seemed important in your code, so...
};
// Note: Constructors don't return anything
}
}
new Foo(() => console.log('baz'));
In a comment you've said:
I see your point, the fact is that my library is new Something().onCreate().onUpdate()
It sounds like you might want to adopt the builder pattern instead:
class Foo {
constructor(callbacks) {
// ...use the callbacks here...
}
// ...
}
Foo.Builder = class {
constructor() {
this.callbacks = {};
}
onCreate(callback) {
this.callbacks.onCreate = callback;
}
onUpdate(callback) {
this.callbacks.onUpdate = callback;
}
// ...
build() {
// Validity checks here, do we have all necessary callbacks?
// Then:
return new Foo(this.callbacks);
}
};
let f = new Foo.Builder().onCreate(() => { /*...*/}).onUpdate(() => { /*... */}).build();
...although to be fair, a lot of the advantages (though not all) of the builder pattern can be realized in JavaScript by just passing an object into constructor directly and doing your validation there, e.g.:
let f = new Foo({
onCreate: () => { /*...*/},
onUpdate: () => { /*...*/}
});
Assuming that onInit is supposed to be some sort of hook to be called synchronously whenever an object is instantiated, you can't solve this on the instance level.
You can make onInit a static function, like so:
class Foo {
constructor() {
// whatever
Foo.onInit();
}
static onInit() {} // empty default
}
Foo.onInit = () => console.log('baz'); // Override default with your own function
const f = new Foo();
const f2 = new Foo();

Converting Singleton JS objects to use ES6 classes

I'm using ES6 with the Webpack es6-transpiler per my article here: http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
Does it make any sense to convert two Singleton objects to use ES6 Classes?
import { CHANGE_EVENT } from "../constants/Constants";
var EventEmitter = require('events').EventEmitter;
var merge = require('react/lib/merge');
var _flash = null;
var BaseStore = merge(EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* #param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
/**
* #param {function} callback
*/
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getFlash: function() {
return _flash;
},
setFlash: function(flash) {
_flash = flash;
}
});
export { BaseStore };
This is file ManagerProducts.jsx that has a singleton that should extend from BaseStore.
/**
* Client side store of the manager_product resource
*/
import { BaseStore } from "./BaseStore";
import { AppDispatcher } from '../dispatcher/AppDispatcher';
import { ActionTypes } from '../constants/Constants';
import { WebAPIUtils } from '../utils/WebAPIUtils';
import { Util } from "../utils/Util";
var merge = require('react/lib/merge');
var _managerProducts = [];
var receiveAllDataError = function(action) {
console.log("receiveAllDataError %j", action);
WebAPIUtils.logAjaxError(action.xhr, action.status, action.err);
};
var ManagerProductStore = merge(BaseStore, {
getAll: function() {
return _managerProducts;
}
});
var receiveAllDataSuccess = function(action) {
_managerProducts = action.data.managerProducts;
//ManagerProductStore.setFlash({ message: "Manager Product data loaded"});
};
ManagerProductStore.dispatchToken = AppDispatcher.register(function(payload) {
var action = payload.action;
if (Util.blank(action.type)) { throw `Invalid action, payload ${JSON.stringify(payload)}`; }
switch(action.type) {
case ActionTypes.RECEIVE_ALL_DATA_SUCCESS:
receiveAllDataSuccess(action);
break;
case ActionTypes.RECEIVE_ALL_DATA_ERROR:
receiveAllDataError(action);
break;
default:
return true;
}
ManagerProductStore.emitChange();
return true;
});
export { ManagerProductStore };
No. Makes no sense.
Here's a really simple example of a singleton object in es6:
let appState = {};
export default appState;
If you really want to use a class in your singleton approach, I would recommend against using "static" as it more confusing than good for a singleton at least for JS and instead return the instance of the class as a singleton like so...
class SomeClassUsedOnlyAsASingleton {
// implementation
}
export default new SomeClassUsedOnlyAsASingleton();
This way you can still use all the class things you like that JavaScript offers but it will reduce the confusion as IMO static isn't fully supported in JavaScript classes anyway as it is in typed languages such as c# or Java as it only supports static methods unless you just fake it and attach them directly to a class (at the time of this writing).
I'd argue that singletons (classes that manage their own singleton lifetime) are unnecessary in any language. That is not to say that singleton lifetime is not useful, just that I prefer that something other than the class manage the lifetime of an object, like a DI container.
That being said, the singleton pattern CAN be applied to JavaScript classes, borrowing the "SingletonEnforcer" pattern that was used in ActionScript. I can see wanting to do something like this when porting an existing code base that uses singletons into ES6.
In this case, the idea is that you make a private (via an un exposed Symbol) static singleton instance, with a public static instance getter. You then restrict the constructor to something that has access to a special singletonEnforcer symbol that is not exposed outside of the module. That way, the constructor fails if anyone other than the singleton tries to "new" it up. It would look something like this:
const singleton = Symbol();
const singletonEnforcer = Symbol()
class SingletonTest {
constructor(enforcer) {
if(enforcer != singletonEnforcer) throw "Cannot construct singleton";
}
static get instance() {
if(!this[singleton]) {
this[singleton] = new SingletonTest(singletonEnforcer);
}
return this[singleton];
}
}
export default SingletonTest
Then you can use it like any other singleton:
import SingletonTest from 'singleton-test';
const instance = SingletonTest.instance;
I had to do the same so here is a simple and direct way of doing a singleton,
curtsy to singleton-classes-in-es6
(original link http://amanvirk.me/singleton-classes-in-es6/)
let instance = null;
class Cache{
constructor() {
if(!instance){
instance = this;
}
// to test whether we have singleton or not
this.time = new Date()
return instance;
}
}
let cache = new Cache()
console.log(cache.time);
setTimeout(function(){
let cache = new Cache();
console.log(cache.time);
},4000);
Both console.log calls should print the same cache.time (Singleton)
In order to create Singleton pattern use a single instance with ES6 classes;
'use strict';
import EventEmitter from 'events';
class Single extends EventEmitter {
constructor() {
this.state = {};
}
getState() {
return this.state;
}
}
export default let single = new Single();
Update: According to #Bergi explanation, below one is not a valid argument.
This works because of (refer to Steven)
> If I understand CommonJS + the browser implementations correctly, the
> output of a module is cached, so export default new MyClass() will
> result in something that behaves as a singleton (only a single
> instance of this class will ever exist per process/client depending on
> env it's running in).
You can find an example here ES6 Singleton.
Note: This pattern is using in Flux Dispacher
Flux: www.npmjs.com/package/flux
Dispacher Example: github.com/facebook/flux/blob/master/examples/flux-todomvc/js/dispatcher/AppDispatcher.js#L16
Singleton class
class SingletonClass {
constructor( name = "", age = 0 ) {
if ( !this.constructor.instance ) {
this.constructor.instance = this;
this.name = name;
this.age = age;
}
return this.constructor.instance;
}
getName() {
return this.name;
}
getAge() {
return this.age;
}
}
const instanceOne = new SingletonClass( "One", 25 );
const instanceTwo = new SingletonClass( "Two", 44 );
console.log( `Name of instanceOne is "${instanceOne.getName()}"` );
console.log( `Name of instanceTwo is "${instanceTwo.getName()}"` );

Categories

Resources