Handle function calls on a class in Node.JS - node.js

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)

Related

What is the right way to export the class to be extended from other classes NodeJs?

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 to use class functions in another class?

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.

How to make Module Functions access a Class context in node.js

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.

Passing different class objects into a function and getting it's properties in Haxe?

Passing different class objects into a function and getting it's properties ?
For example:
I have two different class objects :
screenA = new ScreenA();
screenB = new ScreenB();
I pass the objects in the tween:
switch (state)
{
case States.SCREEN_A:
{
Actuate.tween(screenA, 0.6, {alpha: 1} ).ease(Sine.easeIn).autoVisible (true).onComplete(onComp, [screenA]);
}
case States.SCREEN_B:
{
Actuate.tween(screenB, 0.6, {alpha: 1} ).ease(Sine.easeIn).autoVisible (true).onComplete(onComp, [screenB]);
}
}
Now i want to access a method of the passed object here, when tween completes.
Tween is passing the object but i am unable to cast it in the function to get the object methods.
private function onComp(screen:?)
{
screen.load();
}
And compiler is always asking for the type. I have tried Dynamic / Any but then it says "load method not found", If i pass the object without any type arguments in the function then it is getting it as an object but not the class object.
There're a lot of ways you could do this, but one is with a common interface:
class ScreenA implements OnTweenComplete { ... }
class ScreenB implements OnTweenComplete { ... }
interface OnTweenComplete {
public function on_tween_complete();
}
Then your function is:
private function onComp(screen:OnTweenComplete)
{
screen.on_tween_complete();
}
Or perhaps, type-check it with Std.is and cast it:
private function onComp(screen:Dynamic)
{
if (Std.is(screen, OnTweenComplete)) {
(cast screen).on_tween_complete();
}
}
In this exact example, you can use load in the onComplete callback to simplify your code:
Actuate.tween (screenA, 0.6, { alpha: 1 }).ease (Sine.easeIn).onComplete (screenA.load);

Calling Method of class within it

// What is the technical reason behind this scenarios..?
You're trying to use a statement other than a declaration directly inside the class - rather than within a method. When did you expect the method to get called?
Basically all you can have directly within a type is a bunch of declarations - methods, variables, constructors, events, nested types etc. Method calls (or any other statements) which aren't part of a declaration have to be written within methods, constructors etc.
Method call statement can not be part of a class declaration, but only within Function members declarations scope, such as Methods, Properties, Constructors etc.
For example:
public class ExampleClass
{
private void SayHelloWorld()
{
Console.Writeline("Hello World!");
}
public void CallSayHelloWorldMethod()
{
this.SayHelloWorld();
}
}
At the above example you can see that I call the SayHelloWorld method within the CallSayHelloWorldMethod metod.
Update:
The closest thing I can think of in your case is to use the class's constructor where your method call will be executed as soon as you'll instantiate your class:
public class ExampleClass
{
//The class constructor
public ExampleClass()
{
this.SayHelloWorld();
}
private void SayHelloWorld()
{
Console.Writeline("Hello World!");
}
}
And when you instantiating it, it will be immediately called:
//Your method call will be executed here
ExampleClass exampleClass = new ExampleClass();
You have a few problems... This won't even compile as you are trying to call the method obj.m1() in the class definition.
A obj = new A();
obj.m1(); // Why this code wont work??? --> This must be inside a method
When you create an instance of a class it will create a new member variable called obj which is an instance of A --> A obj = newA() above;
You will now be able to call obj's methods as in your second example.
Also, in order to get this to compile you will need to fix the m2 method:
public void m2() { //--> should have a curly brace
obj.m1(); // But This will work.
}

Resources