The question is how to refer to other static methods from a static method of a class exported from NodeJS module? Here's a setup. I have following modules: test1.js
var Parent = class {
static smethod1 () {
return this.smethod2();
}
static smethod2 () {
return "Testing tube";
}
}
module.exports = {
Parent:Parent
}
Then I have test2.js that requires this module
var mod = require('./test1');
var Parent = mod.Parent;
module.exports = {
sm1: Parent.smethod1,
sm2: Parent.smethod2
}
Finally, I have a code that is being run in run.js
var test2 = require('./test2');
console.log(test2.sm1());
Naturally, I want to see "Testing tube" line printed out. I am getting error
return this.smethod2();
^
TypeError: this.smethod2 is not a function
Of course, there's shenanigans on NodeJS where this refers to a module, but shouldn't it be referring to a function instead ? Is there way to refer to static method smethod2 from smethod1 with current setup ? If not, what are the workarounds ?
The this keyword is kind of weird in JavaScript, and doesn't always refer to your instance like in most class based languages. In your case, when you call test2.sm1(), this is set to the test2 object, which is
{
sm1: Parent.smethod1,
sm2: Parent.smethod2
}
That object does not have a smethod2 function.
this gets set based on how a function is called in JavaScript, specifically with whatever is before the '.': ->test2<-.sm1().
There are several workarounds. First, after defining the Parent class, you could bind this for that function to the class:
var Parent = class {
static smethod1 () {
return this.smethod2();
}
static smethod2 () {
return "Testing tube";
}
}
// bind `this` to `Parent`
Parent.smethod1 = Parent.smethod1.bind(Parent);
module.exports = {
Parent:Parent
}
Alternatively, you could pass Parent as an argument to call or apply, which sets this manually for just that one invocation:
var Parent = require('./test1');
var test2 = require('./test2');
// call `test2.sm1` with a context of `Parent`
console.log(test2.sm1().call(Parent));
Related
While this works as intended
class ClassWithStaticMethod {
static staticMethod() {
return ('staticMethod');
};
static staticMethod2() {
const yee = this.staticMethod();
return 'staticMethod2 '+yee;
};
}
console.log(ClassWithStaticMethod.staticMethod2());
//staticMethod2 staticMethod
This is,
i) have access to the staticMethod() with the class name, and
ii) this method can call another static method within the same class by using "this",
This doesn't work
class ClassWithStaticMethod {
static staticMethod = () => {
return ('staticMethod');
};
static staticMethod2 = () => {
const yee = this.staticMethod;
return 'staticMethod2 '+yee;
};
}
console.log(ClassWithStaticMethod.staticMethod2());
//staticMethod2 undefined
In the sense, that I can still access to the staticMethod() method, but I am not able to access to the other method within the first method. I get undefined, and if I use
const yee = this.staticMethod();
I get an error
error TypeError: _this.staticMethod is not a function
Arrow functions inherit their this from the outer scope rather than their this depending on their calling context. Since staticMethod2 tries to access this.staticMethod, that will only work if this refers to ClassWithStaticMethod - that is, if staticMethod2 is a standard function, not an arrow function.
You also need to invoke this.staticMethod(). (const yee = this.staticMethod; will result in the staticMethod being coerced to a string, rather than being called)
Change those two issues, and it works as expected:
class ClassWithStaticMethod {
static staticMethod = () => {
return ('staticMethod');
};
static staticMethod2 = function() {
const yee = this.staticMethod();
return 'staticMethod2 '+yee;
};
}
console.log(ClassWithStaticMethod.staticMethod2());
That's one quirk with arrow functions when it comes to general use: they have generic scoping of this. (That's why we have to use function() if you want a better call stack). In the second method, this refers to the calling context: window.
As mentioned below in the comment, do not use the short-hand syntax for your convenience; there is a reason we have so many options.
To fix it, you can just use function() to define the second function; or () in the object case.
This, however, would work:
class ClassWithStaticMethod2 {
static staticMethod = () => {
return ('staticMethod');
};
static staticMethod2 = function() {
console.log(this)
const yee = this.staticMethod();
return 'staticMethod2 '+yee;
};
}
Check it out here.
I am trying to access the function from another file like below:
exp1.js
module.exports = function(RED) {
function expIn(config) {
//some code
}
}
I want to access "expIn()" in another file called exp2.js how can i achieve this??
please help me.
As is, you are not exporting expIn(). You are exporting the outer function in which expIn() is declared and defined. expIn() is just a local variable and cannot be accessed outside of the anonymous outer function you are actually exporting. To make it visible to other files, you either have to export it directly or define it on the exported function.
You're missing some code, but you have 3 options for accessing expIn() outside of exp1.js. First is to export it directly
exp1.js
module.exports = function expIn(config) {
// Code...
};
exp2.js
const { expIn } = require('exp1.js');
expIn({/*config*/});
Alternatively, you could add expIn() to the outer function's prototype. This is usually done when you want to export a class with several methods attached to it. You can do this one of 2 ways. First, the method most similar to what you're already doing is
exp1.js
module.exports = function ClassName(/*constructor args*/) {
this.expIn = function expIn(config) {
// Code...
};
// Other initialization...
};
Alternatively, you could define expIn() more explicitly on the prototype using this method:
exp1.js
function ClassName(/*constructor args*/) {
// Initialize class.
}
ClassName.prototype.expIn = function expIn(config) {
// Code...
};
module.exports = ClassName;
Regardless of which of the 2 methods you choose above, you would access it as
const ClassName = require('exp1.js');
let classInstance = new ClassName();
classInstance.expIn({/*config options/*});
One last method you could use is defining expIn() as a static method on the function class. This would look like:
exp1.js
function ClassName(/*constructor args*/) {
// Initialization code...
}
ClassName.expIn = function expIn(config) {
// Code...
};
module.exports = ClassName;
exp2.js
const ClassName = require('exp1.js');
ClassName.expIn(/*config options*/);
This i resolved by adding function out side the function(RED):
module.exports = function(RED) {
}
function expIn(config) {
//some code
}
And then exported as normal like :
module.exports.expIn = expIn;
then it starts working.
I am not sure whether this is a correct method or not but it serves my requirement.
The below code snippet I found on one blogs to avoid if-else statement. This code is very modular and can be easily extended. But I am not able to get this to work.
CatModel.prototype.makeWords = function () {
console.log('inside catmodel')
this.setWord('meow')
this.sayIt()
}
DogModel.prototype.makeWords = function () {
console.log('inside dogmodel')
this.setWord('bark')
this.saySomething()
}
// somewhere else
var makeWords = function (type) {
var model = namespace[type + 'Model']
model.makeWords()
}
makeWords('cat')
Presumably the CatModel and DogModel functions are declared somewhere and setWord and sayIt are also set up on their prototype object.
You'd need to put CatModel and DogModel in an object and refer to it from namespace (which I'd recommend not calling namespace):
var namespace = {
CatModel: CatModel,
DogModel: DogModel
};
Then when creating an instance, use new (you always use new with constructor functions). I'd also put the () on the call even though strictly speaking they're optional if you don't have parameters to pass:
var makeWords = function (type) {
var model = new namespace[type + 'Model']()
// ---------^^^--------------------------^^
model.makeWords()
}
I am trying to create a dynamic function in TypeScript which calls an already existing function like:
let dynamicFunction = new Function("existingFunction(\"asdf\");");
function existingFunction(name: string) {
console.log(name);
}
While debugging in chrome dynamicFunction looks like this:
(function() {
existingFunction("asdf");
})
When I try to execute dynamicFunction, it says "Uncaught ReferenceError: existingFunction is not defined", which is no surprise because it's a different scope, but how can I actually call exisitingFunction inside dynamicFunction?
Any help would be greatly appreciated!
Edit:
to be more precise: I've got a typescript file which contains one module.
This module exports a function which should return the created dynamic function.
The created dynamicFunction is then used in another module which actually contains the exisitingFunction.
I've chosen this approach because I need to convert a given string to an executable condition, which will be executed many times.
For example: convert string "VALUE==1" to:
function () {
return exisitingFunction("VALUE") == 1;
}
A short example of how it should look like:
parser.ts:
export module Parser {
export function getFunction(expression: string) {
// Calculating condition...
let condition = "existingFunction(\"VALUE\") == 1;"
return new Function(condition);
}
}
condition.ts:
import { Parser } from "./parser";
class Condition {
// getting the DynamicFunction
private _dynamicFunction = Parser.getFunction("VALUE==1");
someFunctionInsideCondition() {
// Calling the DynamicFunction
this._dynamicFunction();
}
}
// Maybe this function should be somewhere else?
function existingFunction(name: string) {
console.log(name);
return 1;
}
I hope this explains my problem a little bit better.
From the Function documentation
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called. This is different from using eval with code for a function expression.
so you'll have to pass existingFunction as an argument or define it in the global space.
try with
var existingFunction = function(name: string) {
console.log(name);
}
Also have a look at eval which will give you access to the current scope ...
--- Update
After the question update and considering your comment about not wanting to use eval because of security concerns (with which i totally agree)
The problem is that in the generated function's scope, this is undefined. Making your existingFunction part of the global scope is already a bad idea and between Typescript and the modules architecture doesn't seem possible at all.
So why not passing a context to the generated function?
This will allow you to control how much of your application to expose to the generated function, while giving it access to external methods.
Something along the lines of:
class Parser {
static getFunction(expression) {
let condition = new Function("context", "context.existingFunction(\"VALUE\") == 1;");
return condition;
}
}
class Condition {
constructor() {
this._dynamicFunction = Parser.getFunction("VALUE==1");
}
someFunctionInsideCondition() {
// Calling the DynamicFunction
this._dynamicFunction(this);
}
existingFunction(name) {
console.log("hello " + name);
return 1;
};
}
let c = new Condition();
c.someFunctionInsideCondition();
Of course your context can be a different object instead of this, where you keep all your utility functions.
I had to donwpile (compile it down, my own word) to es2015 to make the example run here, but I made it originally in Typescript and works fine
I would skip the usage of new Function and instead do it as follows.
The parser.ts file would contain this:
export class FunctionGenerator {
constructor(private fn: Function) {}
makeFunction(args: string): Function {
const [variable, val] = args.split("==");
return () => this.fn(variable) == val;
}
}
This is basically a factory that allows creating a series of functions that call the function passed when the factory is created. You can then use makeFunction for the specific checks you want to perform. (Note that I used == like in your question. I much prefer using === unless there's a reason against it.)
It can then be used like this:
import * as parser from "./parser";
let vars = {};
// This is a simulation of your funciton. It just plucks values from `vars`.
function existingFunction(name: string) {
return vars[name];
}
function resetVars() {
vars = {
"VALUE": 1,
"FOO": 2,
"BAR": 3,
};
}
function test(gen) {
const fn1 = gen.makeFunction("VALUE==1");
console.log(fn1(), "should be true");
const fn2 = gen.makeFunction("BAR==3");
console.log(fn2(), "should be true");
vars["BAR"] = 7;
// Call the same function again, but with a new value in `vars`.
console.log(fn2(), "should be false");
const fn3 = gen.makeFunction("BAR==1000");
console.log(fn3(), "should be false");
}
resetVars();
const gen = new parser.FunctionGenerator(existingFunction);
test(gen);
Let's say I have two classes, Base and Child. Base is the base class that Child will be inheriting from. Here's the code to visualize this:
Base.js
function Base(init) {
}
function log() {
console.log('here');
}
Base.prototype.log = log;
module.exports = Base;
Child.js
var Base = require('../Base.js');
var Child = module.exports = function Child(init) {
Base.call(this, init);
};
require('util').inherits(Child, Base);
function test() {
this.log(); // doesn't work
Base.prototype.log(); // Works but is quite ugly
Child.super_.prototype.log(); // Works but is even uglier
}
Child.prototype.test = test;
What I would absolutely love to do is something like this.log() or even log() would be nice. I realize I can set a variable to that in my inherited class, but then I would have to do that for every class that inherits Base, which is definitely not ideal. So my question is, can I do something like this.log() without having to set a variable in the inherited class? Am I misunderstanding something?
Updated Answer:
From your comment below, replying to my statment that this.log() should work:
Well, so that's the thing. When I'm in Child's test function, this is an empty object, so I'm assuming somewhere down the line I'm not getting the proper scope.
You haven't shown how you're calling test, but I suspect that's where the problem is. Provided you call it via a Child instance:
var c = new Child();
c.test();
...then within the call, this will be the child instance, which will inherit (indirectly) the Parent.prototype object with its log property.
But how you call it is important. This wouldn't work, for instance:
var c = new Child();
var f = c.test;
f();
If you do that, within the call to the function, this will be the global object (or undefined if you're in strict mode), not a Child instance. This is because in JavaScript, this is set primarily by how a function is called, and calling it like that doesn't set this to what you want.
This matters for callbacks, because passing in c.test as a callback:
someFunctionThatUsesACallback(c.test);
...means the code calling back won't set this for you.
If you need to do that, Function#bind will help:
var f = c.test.bind(c); // Returns a version of c.test that, when called,
// will have `this` set to `c`
f(); // Works, `this` is the `Child` instance
And similarly:
someFunctionThatUsesACallback(c.test.bind(c));
More (on my blog):
Mythical methods
You must remember this
Original Answer:
If you set up the prototype hierarchy correctly, and Child.prototype doesn't have log on it (and you don't put a log property on instances), then you should be able to use this.log(); just fine. If you can't, then the hierarchy hasn't been set up correctly.
I don't know what util.inherits does, but setting up the relationship between Child and Parent correctly isn't complicated:
function Parent() {
}
Parent.prototype.log = function() {
console.log("log called");
};
function Child () {
Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // This line is largely optional, but a good idea
// Usage
var c = new Child();
c.log(); // "log called"
But if you override log in your Child.prototype or assign a log property to instances, and you want to use Parent's version of log, then of course you can't just use this.log() because the property doesn't refer to Parent.prototype.log anymore.
When you need to call the parent version of something (I call them "supercalls," and I don't think that's original), you have to do more work:
I usually set up hierarchies like this by passing the parent constructor into a function I use to build the child, e.g.:
var Child = (function(Super) {
var pp = Super.prototype;
function Child() {
}
Child.prototype = Object.create(pp);
Child.prototype.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
return Child;
})(Parent);
By always using that pattern, I avoid having to write Parent inside the Child code (I use the Super arg instead), so if I need to rebase Child, I just change what I pass into the function.
Because that's fairly ugly (for instance, it's unclear at the top of Child that it derives from Parent, since Parent is at the bottom) and involves boilerplate code I don't feel the need to write again every time, I wrote a simple helper script for it I call Lineage, which makes it look like this:
var Child = Lineage.define(Parent, function(p, pp) {
p.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
});
Note that Lineage passes in both the Child and Parent prototypes as arguments, making it concise to use them (and since you get to pick those argumetn names, you can use whatever terminology works for you — I use p for the prototype of the "class" being created [Child in the above], and pp for the parent's prototype, etc.).
The standard inherits function from node.js is (in my humble opinion) very bad code. Instead I prefer to use augment to create classes:
// base.js
var augment = require("augment");
var Base = module.exports = augment(Object, function () {
this.constructor = function (init) {
};
this.log = function () {
console.log("here");
};
});
// child.js
var augment = require("augment");
var Base = require("./base");
var Child = module.exports = augment(Base, function (base) {
this.constructor = function (init) {
base.constructor.call(this, init);
};
this.test = function () {
this.log();
};
});
In addition augment.js is just 20 lines of code and can be used everywhere.
Just as an FYI, I ended up putting this in the global variable that Node creates for you. I realize that's bad practice, but it's a logging mechanism that needs to be used by any class, controller, etc., so I don't think it's that terrible of a solution.
However, in Compound, you can create no_eval controllers, which means they look like typical prototypical functions... so you can essentially create a mixin, or I can require my mixin and use it like a class... like this:
var ControllerMixin = require(process.cwd() + 'app/mixins/ControllerMixin.js');
var Log;
var LoggerController = module.exports = function LoggerController(init) {
ControllerMixin.call(this, init); // mixin approach
Log = require(process.cwd() + 'app/utils/LoggerMixin.js')(init); // class approach
};
LoggerController.prototype.index = function index(controller) {
controller.logMessage('blah'); // using mixin
Log.logError('hi'); // using class
global.logWarning('yep'); // global approach
return controller.send({success: true});
};
So there are options... just have to find what you think is the best approach.
Every answer I see online either looks complicated, or relies on external libraries. Why not just boil down to the basics, assuming you use a custom type design pattern, which is very similar to traditional OOP.
parent.js
//the main parent class
// class Parent
module.exports = Parent;
function Parent(a) {
if (!(this instanceof Parent)) {
return new Parent(a);
}
this.a = a; //Some parent variable
}
Parent.prototype = {
// Instantiate child:
getChild: function() {
var Child = require('./child');
return new Child(this);
},
// Some parent function, print some text:
printText: function(text) {
console.log(text);
}
};
child.js
//Similar to class Child extends Parent
module.exports = Child;
function Child(parent) {
this.parent = parent;
}
Child.prototype = {
// Prints Parent Variable:
printParentVariable: function() {
console.log(this.parent.a);
},
// Calls Parent Function:
callParentFunction: function() {
this.parent.printText('Child calling parent function.');
}
};
test.js
var parent = require('./parent')('parent text'); //instantiate parent with some text
var child = parent.getChild(); //create instance of a child
//*** Child has full access to its parents variables and methods ***//
console.log(child.parent.a); //Print the parent text "parent text"
child.printParentVariable(); //Child method which prints the parent variable "parent text", identical to line above.
child.parent.printText('Child calling parent'); //Call parent method, to print provided text
child.callParentFunction(); //Calls parent method, identical to above.