How to evaluate classes from files applied globally using Eval - node.js - javascript

Parent script including childscript
const fs = require('fs');
function include(f) {
eval.apply(global,[fs.readFileSync(f).toString()])
}
include(__dirname+'/fileToRead.js');
hi();
let childVar = new child();
------------------------- childScript ------------------------------
function hi() {
console.log("hi");
}
class baseObj {
constructor(){
console.log("hello")
}
}
class child extends baseObj{
constructor(){
super();
}
}
----------------------------result-----------------------------------
// the hi function executes
hi
// the instance does not
let childVar = new child();
^
ReferenceError: child is not defined
---------------------Conclusive question---------------------
how do would I get the eval method to globalize the child class as well as the baseObj class using my include method provided.
---------------------------------disclaimer------------------
Disclaimer : I know modules exist and I think they are great , but when you are doing something so large server side its a huge pain to keep track of exports and imports.
Especially since cyclic references exist. Not to mention every single time you create a file you need to add whatever functionality to it with require statements and find the path to those files and then export whatever functionality you are creating in that file to go to other files .
I wish to avoid modules using this method for the most part and make it similar to dealing with client side import statements.
Thanks for the help and have a nice day guys ! :)

Your problem boils down to this:
eval('function foo() {}')
console.log(foo) // ok
eval('class bar {}')
console.log(bar) // nope
This is because
Bindings introduced by let, const, or class declarations are always instantiated in a new LexicalEnvironment. (https://tc39.es/ecma262/#sec-performeval, NOTE)
If you really want to replace the stock require, for whatever reason, try using the VM API (this is what require uses under the hood).

If you really-really need this, this is an option, as class (unlike var) does not create global bindings:
var baseObj = class {
constructor() {
console.log("hello")
}
}
var child = class extends baseObj {
constructor() {
super();
}
}

Related

How to Call Global Variables From Constructors

I have a class that looks like this:
class MyClass {
constructor() {
this.field = 42;
}
method() {
return "Hello world!";
}
}
I want to define an instance of it as a global variable, so I registered it:
global.MyObject= new MyClass();
Which means this will now work:
console.log(MyObject.field); // 42
console.log(MyObject.method()); // Hello world!
However, whenever I call that same code from another class it suddenly becomes a lot more random:
class OtherClass {
constructor() {
console.log(MyObject.field); // undefined
console.log(MyObject.method()); // TypeError: MyObject.method is not a function
}
}
Sometimes this works, sometimes it doesn't. I am not able to find out when it works and when it doesn't, only that it isn't totally random. Called from the same place, the constructor either works or not. Which does not help to isolate the problem.
It seems that when the class's constructor is called from a module that does not have a direct require('my-class') it will not work - even when OtherClass has that requironment? Even when every other module has that require? Which does not make any sense.
I tried it with two modules A and B. If A defines global variables, B can access them just fine even without a require - as long as someone else has it.
So... I'm stumped at how this works. Might be a silly JavaScript gimmick, I'm not a native JavaScript developer.
My setup looks like this:
src/
ActualCode (uses functionality that will create OtherClass)
test/
mock/
MyClass
OtherClass (require('MyClass'))
ActualCodeTest (require('ActualCode'), require('OtherClass')
The constructor in OtherClass will be able to access MyClass when called from MyClass and OtherClass, but not from ActualCode or ActualCodeTest. Even if called in sequence (so the global variable definitively exists).
Which means changing parameters and adding a require is out of the question, since the ActualCode should never know test code.
The problem seems to be with the Mocha framework. The global variable cannot be accessed inside the "it":
console.log(MyObject.field); // 42
it('test', () => {
console.log(MyObject.field); // undefined
}
If I remove the surrounding code it will (obviously) work.
How do I call global variables from a class's constructor?
This sample code works as expected when you have it all in a single file:
$ cat sample.js
class MyClass {
constructor() {
this.field = 42;
}
method() {
return "Hello world!";
}
}
global.MyObject = new MyClass();
class OtherClass {
constructor(props) {
console.log(MyObject.field);
console.log(MyObject.method());
}
}
new OtherClass();
$ node sample
42
Hello world!
I suspect the confusion comes in the sequence those lines are run when you're loading the modules. Node's module-loading code will run every line in the sequence they are encountered.
The problem is that Mocha can't access global variables in its tests. I could not find the
relevant bug for this behavior, but at least a person with the same problem.
Since the global variables are only used in the tests, I get to have an easy solution:
global.MyObject= new MyClass();
module.exports.MyObject = MyObject;
And this in the test:
before(() => {
global.MyObject = require('./mock/my-class').MyObject;
});
It's probably a good idea to add a TODO so you can revisit this issue every now and then in case the Mocha crew fixes it.

Initiate and return a class within a class in Node.js

I have this class which we're going to call Connection, and there's a function in this class named Disconnect which returns a class named PartialConnection. There are some arguments for both classes, but that shouldn't be taken into effect because it's quite complicated for such an example.
This is the class structure I'm working with as a sketch:
const BaseConnection = require("./BaseConnection.js");
const PartialConnection = require("./PartialConnection.js");
class Connection extends BaseConnection { // BaseConnection is also a class with standard variables every type of connection should have. PartialConnection also extends from this.
constructor () {
...
}
Disconnect() {
return new PartialConnection();
}
}
Before you all ask, the path to ./PartialConnection.js is correct and it's set with module.exports = PartialConnection; with PartialConnection being the class name.
File PartialConnection.js
const Connection = require("./Connection");
const BaseCon = require("./BaseConnection");
class PartialConnection extends BaseCon {
constructor () {
...
}
}
module.exports = PartialConnection;
Although, I must say that the colouring of the module.exports = PartialConnection is off like shown here: https://imgur.com/a/pB9yLW5 - I also should say that, when executing the same function but for the PartialConnection to Connection, it just works fine. It has something to do with circular references.
When I create a new instance of Connection and run the Disconnect function, it returns the following error:
/Users/---/Desktop/Projects/QDB/lib/Connections/Connection.js:87
return new PartialConnection();
^
TypeError: PartialConnection is not a constructor
at Connection.Disconnect (/Users/---/Desktop/Projects/QDB/lib/Connections/Connection.js:87:16)
at process.<anonymous> (/Users/---/Desktop/Projects/QDB/lib/Connections/Connection.js:76:75)
at process.emit (events.js:219:5)
(I blanked out my name for privacy.)
As you can see, it seems like I can't initiate and return a new class of some sort. This used to work about a few weeks ago, but now it doesn't.
Version;
$ node -v
v13.3.0
$ npm -v
6.14.2
And for clarification - I'd like it to almost-literally terminate the current class and return a new class that doesn't allow you to make adjustments to the Connection class.
If you have any solutions or if you can help in any way, it's much appreciated!
Alright, so I have experimented a bit more and found out that, if you require the class within the function instead of at the beginning of the file, it caches instantly and you're able to call it instead of having it return an empty object.
const BaseConnection = require("./BaseConnection");
class Connection extends BaseConnection {
constructor () {
...
}
Disconnect() {
const PartialConnection = require("./PartialConnection");
return new PartialConnection();
}
}
If you have any other answers, later on, feel free to share!

Define 'real' private methods in ES6 Module/Class in a nodejs only environment without any information leak

I know that there is no REAL private method INSIDE ES6 classes. However I was playing around a little bit and discovered something good - maybe...
As I mentioned it is not possible to not expose properties of an object. But I've tried to achieve somewhat of OOP programming as I divided my classes into seperate files and then exported those classes like:
class MyClass {
constructor() {
/**
* Initialize stuff...
*/
}
myMethod() {
/**
* Do public stuff...
*/
}
}
// expose class to environment.
export default MyClass;
So I can import the class:
import MyClass from './MyClass.js';
Of course myMethod is accessible from any other file which imported the module. Sinced I was in need of variables and functions beeing accessible only by the class I've tried this:
// private variable outside of class scope but still accessible.
let possiblePrivateVariable = 'am I a private variable?';
class MyClass {
constructor() {
/**
* Initialize stuff...
*/
}
myMethod() {
// run private method.
console.log(_possiblePrivateMethod());
// show private variable.
console.log(possiblePrivateVariable);
}
}
// private function outside of class scope but still accessible.
function _possiblePrivateMethod() {
return 'am I a private method?';
}
// expose class to environment.
export default MyClass;
Now you can't access the private variable and private method:
// Import class to newFile.js and use it.
import MyClass from './MyClass.js';
const exposedClass = new MyClass();
exposedClass.possiblePrivateVariable; // -> undefined.
exposedClass._possiblePrivateMethod(); // -> undefined.
exposedClass. myMethod(); // -> logs: am I a private method?
// am I a private variable?
It is obvious that those are feeling like beeing 'private' because I am not exposing them with the word export. My question is if this method can be considered creating private variables and methods? And if the Method I've shown has any other possible leakage while running the code?
Regards,
Megajin
Sidenote: I do not need browser support since it is a NodeJS only environment. I am using NodeJS v8.1.4 and use babel in my npm start script so I can use import without any TypeError's.
I should mention as well that I'm aware that this question could be seen as a duplicate but it is not because this question is not about private properties, variables and methods inside a class but outside it.
My question is if this method can be considered creating private
variables and methods?
Yes it's an actual working solution to address the fact that ES6/7/8 do not handle privacy in classes.
And if the Method I've shown has any other possible leakage while
running the code?
Fast answer : No leak
Detailed answer:
In your private function system, what makes the function private is that in javascript the scope of a function is defined by where it's defined. In your case the file.
If you do not export the function outside the file, there is no way to access it. Like you cannot access the function in the following mainstream example :
function toto() {
const tmpToto = () => console.log('Hello');
// I can access tmpToto from here
tmpToto();
return false;
}
// I cannot access tmpToto from here
Here you get a nice explanation about scopes
More infos according to comment
How would you solve the problem that multiple class instances will
share the 'out of scope' variables?
You can use IIFE(Immediately-invoked function expression) as described by #Son JoungHo in this post.
let Name = (function() {
const _privateHello = function() {}
class Name {
constructor() {}
publicMethod() {
_privateHello();
}
}
return Name;
})();

Pass TypeScript object to Window in Electron app

If I have a simple typescript class that just prints to the screen, like below, how can I access it on the front end in a simpler way?
speak.ts
export class Speak {
public write() {
console.log("Hello");
}
}
I know you are able to use
index.html
<script>
var x = require('./speak');
x.Speak.prototype.write(); // Prints "Hello"
</script>
The require statement has to assign to a variable for me to access this class. I'm not able to access it using require('./speak'); on its own, trying to bring it into global scope.
Having to preface every command with "x.Speak.prototype" is a bit verbose, and could easily become much longer when multiple classes and interfaces are introduced.
I feel like I'm not doing this the right way. How can I bring data/functions over from TypeScript classes to operate on the front end?
UPDATE
When I try something like below in my index.html file
<script>
var speak = new Speak();
speak.write("some other stuff");
</script>
I get an error: Uncaught ReferenceError: Speak is not defined
There are two things involved.
ES6 -> CommonJS interop
class syntax
For the first point, you are declaring an ES6 module while consuming it in commonJs syntax.
that's why you need the extra X to hold on to the module object in CJS:
var X = require('./speak');
var speak = new X.Speak();
// or accessing the `Speak` class directly:
var Speak = require('./speak').Speak;
var speak = new Speak();
If you consume the same code in ES6, it would be:
import { Speak } from './speak'
const s = new Speak();
// or
import * as X from './speak'
const s = new X.Speak();
Of course, ESM (ES6 Module system) is not available in every browser, so you need to transpile your TypeScript code down to ES5 and use some loader mechanism to load the module (like requireJS).
For the second point, you are writing a class. so you typically would create an instance of Speak and use it (following code assume you consume the code in a module, to avoid confusion with the first point):
var speak = new Speak();
speak.write();
If you don't need an instance, you can use a static method or just function:
export class Speak {
static write() { ... }
}
// usage:
Speak.write();
// function
export function write() { ... }
// usage:
write();

How create static functions/objects in javascript/nodejs (ES6)

I want to create a static class using Javascript/Node JS. I used google but i can't find any usefull example.
I want to create in Javascript ES6 something like this (C#):
public static MyStaticClass {
public static void someMethod() {
//do stuff here
}
}
For now, I have this class, but I think that this code will creates a new instance every time that it be called from "require".
function MyStaticClass() {
let someMethod = () => {
//do some stuff
}
}
var myInstance = new MyStaticClass();
module.exports = factory;
Note that JS is prototype-based programming, instead of class-based.
Instead of creating the class multiple times to access its method, you can just create a method in an object, like
var MyStaticClass = {
someMethod: function () {
console.log('Doing someMethod');
}
}
MyStaticClass.someMethod(); // Doing someMethod
Since in JS, everything is an object (except primitive types + undefined + null). Like when you create someMethod function above, you actually created a new function object that can be accessed with someMethod inside MyStaticClass object. (That's why you can access the properties of someMethod object like MyStaticClass.someMethod.prototype or MyStaticClass.someMethod.name)
However, if you find it more convenient to use class. ES6 now works with static methods.
E.g.
MyStaticClass.js
class MyStaticClass {
static someMethod () {
console.log('Doing someMethod');
}
static anotherMethod () {
console.log('Doing anotherMethod');
}
}
module.exports = MyStaticClass;
Main.js
var MyStaticClass = require("./MyStaticClass");
MyStaticClass.someMethod(); // Doing someMethod
MyStaticClass.anotherMethod(); // Doing anotherMethod
I would use an object literal:
const myObject = {
someMethod() {
// do stuff here
}
}
module.exports = myObject;
You can use the static keyword to define a method for a class
class MyStatisticsClass {
static someMethod() {
return "MyStatisticsClass static method"
}
}
console.log(MyStatisticsClass.someMethod());
I am late to the party, but it seems one aspect is missing.
NodeJs doesn't execute your module code every time you use require. It is more like a kind of stateful container, that initializes your module once and passes this instance each time you use require.
I am nodejs noobie, so don't use following without discussion with someone more mature, but I adhere for software principles, that considers using static methods evil (e.g. it is better to construct interface contracts against interfaces, not against concrete interface implementation; you just don't simply make it with static methods).
In other languages, it is usual corner stone to have some IoC container, that has all of your modules registered and solves passing of dependencies for you. Then you write everything as "Service" classes. Service class is instantiated most often only once per application life-time and every another piece of code, that requires it gets the same instance from the IoC container.
So I use something similar, without the comfort of IoC :( :
Note in this example - A's constructor is called only once, althought required 3 times.
Test.ts:
import {a} from './A';
import {b} from './B';
import {c} from './C';
console.log(c, b);
A.ts:
export class A
{
constructor(){
console.log('"A" constructor called');
}
foo() {
console.log('foo');
}
}
export const a = new A();
B.ts:
import {a, A} from './A';
export class B
{
constructor(a: A)
{
console.log('"B" constructor called, got a:', a);
a.foo();
}
}
export const b = new B(a);
C.ts:
//The same as B.ts
Result:
node test.js
"A" constructor called
"B" constructor called, got a: A {}
foo
"C" constructor called, got a: A {}
foo
C {} B {}
So as You can see - no static methods. Works with instances (althought not with interfaces in this simplified example). A's constructor called only once.
An IICE (Immediately Invoked Class Expression) :
const A = new (class a{Print(){console.log('I Am static function')}});();
A.Print();
// console.log(a);
// **Uncaught ReferenceError: a is not defined at <anonymous>:`enter code here`1:1**
// 'A' Variable is the only reference to the class a, and the only instance of it.
Or even better, a nameless class:
const A = new class {Print(){console.log('I Am static function')}};

Categories

Resources