I am trying to use a more object oriented approach with node.js "embedding" functions ( if that is the right word ) so that I can use functions and objects as if they are in the objects context. It might be easier to show in code.
I realise you can assign individual functions in the constructor - and this would work.. but I am not sure how to assign a whole module with functions to all the functions can access values in the objects context.
So , my question is : How can I assign a module to a class so that all the functions within the module can access everything within the objects context.
app.js
const myFunctions = require('./functions');
class myClass{
constructor() {
this.myFunctions = myFunctions ;
}
}
var mc = new myClass();
mc.myObject = { aaa: 'test'}
mc.myFunctions.outputValue(); // << should output the previous value set.
functions.js
function outputValue(){
console.log(this.myObject)
}
module.exports = {
outputValue
}
You could do it in two ways:
1 - Bound your class instance this to each one of the external functions:
class myClass {
constructor() {
this.myFunctions = {
outputValue: myFunctions.outputValue.bind(this),
};
}
}
2 - Define a method in your class to call the external functions, like:
class myClass {
constructor() {
}
callFunction(fnName) {
const fn = myFunctions[fnName];
if (fn) fn.apply(this);
}
}
Said that I will recommend avoiding using classes and this at all (at least it's completely necessary) and instead use pure functions, functions that only receive parameters does some processing and return some value.
The best way to do this which also follows the injection pattern,
const myClass = new myClass(myFunctions);
myClass.outputValue.bind(myClass);
Here it binds and inject all the class objects so it is accessible to other methods in different class .
Note : Look at "bind" usage.
Related
I want to add a metrics class to my code. What is the difference between
class MyMetrics {
constructor () {
if (!Singleton.instance) {
Singleton.instance = new Metrics()
}
return Singleton.instance
}
}
const metrics = new MyMetrics()
and
export const metrics = new Metrics()
Wouldn't each module that imported metrics be using the same Metrics instance?
Are they functionally the same for my usage? Which would be recommended?
Wouldn't each module that imported metrics be using the same Metrics instance?
Yes, they would.
Are they functionally the same for my usage?
As long as A) you aren't creating other instances within the module and B) you aren't exporting Metrics, yes, almost. But one thing to remember is that any code that has access to your metrics import has access to your Metrics constructor, indirectly via the constructor property metrics inherits from Metrics.prototype:
import { metrics } from "./your-module.js";
const newMetrics = new metrics.constructor();
You might think that with the singleton, you've avoided that, but that's easily defeated as instance is public:
import { metrics } from "./your-module.js";
const Metrics = metrics.constructor;
Metrics.instance = null;
const newMetrics = new Metrics();
So you might want to make it private (either using a static private property, or just using metrics itself to check if you've created it).
Which would be recommended?
That's a matter of opinion. But you might not even need a class at all. You could:
Just make an object directly without a constructor function.
Export functions and close over module-private variables.
For instance, consider this (fairly silly) class:
// stuff.js
class Stuff {
#items = new Map();
constructor() {
// ...pretend there's singleton logic here...
}
put(key, value) {
this.#items.set(key, value);
}
get(key) {
return this.#items.get(key);
}
}
export const stuff = new Stuff();
The way you use that is:
import { stuff } from "./stuff.js";
stuff.put("this", "that");
stuff.get("this"); // "that"
You could just get rid of the class entirely:
// stuff.js
const items = new Map();
export const stuff = {
put(key, value) {
items.set(key, value);
},
get(key) {
return items.get(key);
}
};
Usage would be the same:
import { stuff } from "./stuff.js";
stuff.put("this", "that");
stuff.get("this"); // "that"
Or you could just export put and get:
// stuff.js
const items = new Map();
export const put = (key, value) => {
items.set(key, value);
};
export const get = (key) => items.get(key);
Then usage is:
import { get, put } from "./stuff.js";
put("this", "that");
get("this"); // "that"
Or if those names may conflict with other things:
import { get as getStuff, put as putStuff } from "./stuff.js";
putStuff("this", "that");
getStuff("this"); // "that"
So you have lots of options to choose from. Constructor functions (including ones created with class syntax) are useful if you need to construct multiple objects with shared characteristics, but if you aren't doing that (and you aren't with a singleton), just writing the object directly or (with modules) exporting the things it can do directly may be good options for you.
Base class looks like this:
class BaseReport {
constructor(reportName) {
this.reportName = reportName;
}
async generateReport(accountId, request) {
let results = await this.getDataFromDb(request);
results = this.formatResults(results);
return updatedResults;
}
formatResults(data) {
//Some logig here
return result
}
getDataFromDb(request) {
//Logic to get data from database
return errorRequest;
}
}
module.exports = BaseReport;
The I have another class that extends Base class:
const BaseReport = require("./base.service");
class DataReport extends BaseReport {
constructor() {
super('dataReport');
}
formatResults(data) {
//Logic to format results in a different way
return data;
}
}
module.exports = new DataReport();
So far everything works well. DataReport class doesn't need to implement the method getDataFromDB because it is inherited from BaseReport class.
The problem starts when I am writing unit/integration tests.
When I try to stub function getData() it is not working (it is not being stubbed but instead it is calling the method and making the database call.
I understand WHY is happening... In BaseReport class I am exporting the class itself. So when I create an object on my unit tests and try to stub the function, that is not the same method and object which is initialized when the application is running. Every time you use the keyword "new" creates a new object and has its own methods.
If I want to stub a method from DataReport class it works fine because in there I am exporting an object of that class (module.exports = new DataReport();). In this case, it can only exist one copy of the object and so only one copy of the methods as well.
Now I can not do the same for BaseReport class because my understanding is that you CAN NOT extend BaseReport class if I exported a new object (module.exports = new BaseReport();).
What is the proper way to implement this in order to also have the unit tests working??
How can i use class instance in another class like a pointer in C++ to class instance functions?
Example:
class A {
constructor()
{
this.block = [];
}
method()
{
return this.blocks.length;
}
}
another class:
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method(); // here i'm getting cannot get length of undefined
}
}
If i'm trying to to like that i'm getting problems to call it
You can try this. Here, when creating B class's instance I give into it an A class's instance as argument. Then inside B we can call A instance's methods, and access its properties.
Also, as #ViaTech posted you can use static methods to access them without needing to initialize an object of the class. That is what static methods is. Refer Static Methods
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method();
}
}
class A {
constructor()
{
}
method()
{
console.log("A's method");
}
}
var a = new A();
var b = new B(a);
b.method(); // A's method
You can easily do this in JS by calling a static method like so:
class A {
static write(){ //static method
console.log("Called write from A");
}
}
class B {
doIt(){
A.write();
}
}
let b = new B();
b.doIt();
Option 2, you instantiate the class in the constructor of the other like so:
class A {
write(){
console.log("Non-static write() called from class A");
}
}
class B {
constructor() {
this.a = new A();
}
doIt(){
this.a.write();
}
}
let b = new B();
b.doIt();
There are a few ways:
I accidentally switched between PHP and Javascript, but the principles are the same for both)
Use static functions:
Normally, you have a this in the class. Say you have this code:
class Car {
let color;
public function setColor(newColor){ this.color = newColor;}
}
let car = new Car();
car->setColor('green')`
The setColor function's this refers to that car. You can make let anotherCar = new Car(), then when you do anotherCar->setColor('red') you only change that car, not the first one. Simplistic: You can create multiple instances.
If you do not need that, but need the class once, you can make it static. A simple way to explain would be "you have a collection of seperate functions, just put into a wrapping class (which doesn't do a lot really)". For instance, you might have some sanatizing methods:
class Sanitize {
static function makeHtmlSave(input){
return doYourMagicHere(input);
}
static function removeXssCode(input){
return doMoreMagicHere(input);
}
}
This way, you can reuse it multiple times. If you want to use it, you do Sanitize::makeHtmlSave(someCode) where you need it. There isn't a Sanitize thing, it's just a wrapper to access the frunctions inside it.
Use extend:
You can extend a class. Say you have a generic class Vehicle, which has some properties (eg a motor, numberWeels, color) and you can extend that with more specific classes:
class Vehicle {
let color;
public function setColor(newColor){ this.color = newColor}
}
class Car extends Vehicle {
let hasAirco = false;
public function hasAirco(newValue){ this.hasAirco = newValue};
}
If you do let car = new Car(), you get a Car object, that extends/enlarges/complements the Vehicle class, so you can use both its (public) functions. Internally, Car can use the functions of Vehicle too.
Just pass it
class One {
// some stuff
}
class Two{
let otherObject;
construct(givenObject){
this.otherObject = givenObject;
}
}
You can now do this let a = new One(); let b = new Two(a);. You can not use the functions of One inside Two, but you can still use a->doSomething(). This solution feels like the easiest, but it almost never is. Classes/objects are tricky stuff, but I've rarely uses this solutions. There are use cases, but often it's a bad smell indicator.
Assuming that you have a class
class MyClass {
world() {
console.log("hello world");
}
}
I can run the method similar to the following:
var hello = new MyClass();
hello.world();
# outputs: hello world
Is there a way to handle direct function calls on an object? For example:
hello();
Returns: TypeError: hello is not a function.
Can I make this call a default function? For example, similar to PHP's invoke function ...
We can only make something callable in JavaScript if that thing is an object which, at some point, delegates to Function.prototype. Therefore, our class will need to extend Function or extend from a class which extends Function. We also need to be able to access instance variables from our class object (in order to call invoke()), so it needs to be bound to itself. This binding can only happen in the constructor.
Since our class will inherit from Function, we need to call super before being able to use this . However, the Function constructor actually takes a code string, which we won't have, because we want to be able to set invoke later on. So we'll need to extend Function in a different class which will be the parent class to our class and which will do the work of setting the prototype of our dummy function (which we need in order to be able to call the returned object). Bringing all of this together, we get:
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class MyClass extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
invoke() {
console.log("Hello, world!");
}
}
x = new MyClass();
x(); //prints "Hello, world!"
I mostly adapted the techniques found in this answer in order to do this.
An interesting aspect of using this technique is that you could name MyClass something like Callable and remove the invoke method - then any class which extends Callable would become callable as long as it had an invoke() method. In fact...
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Callable extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
}
class CallableHello extends Callable {
invoke() {
console.log("Hello, world!");
}
}
class CallableBye extends Callable {
invoke() {
console.log("Goodbye cruel world!");
}
}
x = new CallableHello();
x(); //prints "Hello, world!"
y = new CallableBye();
y(); //prints "Goodbye cruel world!"
(Of course, you could get the same effect by setting properties on function objects, but this is more consistent I guess)
I am using ES6 syntax style to make the inheritance class in node.js, there is two classes, in which the base class is to build a mqtt client, and the inherited class is to extend the base class.
However, the problem is the inherited class can not use the variable defined in the base class.
For example, in my base class, there is a public variable called : this.mqtt_client, when I tried to use this variable in the inherited class, it always gives a undefined issue
My base class is as followed
var mqtt = require('mqtt'),
EventEmitter = require('events').EventEmitter;
class MQTTBaseClass extends EventEmitter{
constructor( option) {
super();
this.mqtt_client = null;
this.uri = option.uri;
this.mqttOptions.clientId = option.clientId;
}
init(uri, mqttOptions){
this.mqtt_client = mqtt.connect( uri , mqttOptions );
this.mqtt_client.on('connect', onConnectionSuccess);
this.mqtt_client.on('error',onConnectionError);
this.mqtt_client.on('message',onMessageReceived);
............
}
}
class MQTTClass2 extends MQTTBaseClass{
constructor(option) {
super(option);
var self = this;
var interval = setInterval(
function() {
self.mqttClient.publish('dddd' , 'ddd' , { retain: false },function(err){
})
}, 5000);
}
..............
}
I've made the assumption that the base class init function is being called that defines this.mqtt_client.
The issue appears to be a misspelling, you are using self.mqttClient where you should be using self.mqtt_client.
As a side note you should attempt to use a common variable naming scheme to avoid issues like this in the future: most Javascript code is written using camel case, but there is no rule against using underscores. The important thing is to be consistent.
The error is completely correct; mqttClient is undefined.
The unrelated mqtt_client field from the base class doesn't change anything.