is this use of eval in a node server a bad idea? - node.js

I want to create an object dynamically in node. To do that i used a code like this.
Is this use of eval in a node server a bad idea?
var a1 = require(./a1.js),
a2 = require(./a2.js),
...
aN = require(./aN.js);
function createObj(pObjName, pObjValue){
var tmp = new eval(pObjName)(pObjValue);
//where pObjName is a1 or a1 or .... or aN
}

From what you're showing, there's no need to use eval:
const Classes = {
a1 : require('./a1'),
a2 : require('./a2'),
...
};
function createObj(pObjName, pObjValue){
var tmp = new Classes[pObjName](pObjValue);
...
}

Seems like you want to create objects with a set of properties?
You might want to look at the Object.create()-method

If you want to save yourself the time of declaring all of those dependencies, you could even write a function without using eval that handles the case even more efficiently:
function createObj(pObjName, pObjValue) {
var tmp = new (require('./' + pObjName))(pObjValue);
// ...
}
Please note that this is only safe if createObj() is guaranteed to be invoked with a pObjName that is what you expect, otherwise you'll need to validate it first, possibly something like this:
function createObj(pObjName, pObjValue) {
if (!/^a\d$/.test(pObjName)) {
throw new TypeError('invalid name')
}
var tmp = new (require('./' + pObjName))(pObjValue);
// ...
}

Related

How to update a module.exports properly?

I have this file that stores some of my environment variables.
Let's call it generalEnv.js
module.exports = {
CONSTANT_1: process.env.CONSTANT_1,
CONSTANT_2: process.env.CONSTANT_2
};
When the app initializes, I don't put the value of process.env.CONSTANT_1 in the env variables yet because I have to look into some places first if it exists(mongodb for instance). If it does not exists on mongodb, I will add a value into process.env.CONSTANT_1 and I was expecting that the value will reflect on generalEnv now.
When I tried accessing the CONSTANT_1 in another file.
Let's call it getConstantOne.js
const { CONSTANT_1 } = require('./generalEnv');
module.exports = () => {
// I was expecting that CONSTANT_1 will have a value here now
if(!CONSTANT_1) {
// do something
}
return CONSTANT_1
}
it does not reflect.. how do I update the closure of generalEnv.js for process.env.CONSTANT_1 to reflect on CONSTANT_1?
When assigning to a variable (or a value in an object/element in an array), the assignment will replace the value, not modify it. Therefore, any "copies" of that value will not be affected, and remain the same. Consider this example:
let a = 0;
let b = a;
a = 1;
What happens to b? Answer: Its value is 0.
To work around this we need some way of modifying the value instead of replacing it. Unfortunately, "primitive types" (strings/numbers/booleans etc.) cannot be modified in javascript. There are types that can be modified however, such as objects. You could solve this by wrapping your variables in an object called "env".
let env: {
CONSTANT_1: process.env.CONSTANT_1,
CONSTANT_2: process.env.CONSTANT_2
}
modules.exports = { env }
and then to modify:
env.CONSTANT_1 = "new value"
and to access:
if (!env.CONSTANT_1) { ... }

Revert variables inside a Loop in Node JS

I am trying one logic in Node JS code which looks something like below:-
var startPersons1 = JSON.parse(JSON.stringify(persons1));
var startPersons2 = JSON.parse(JSON.stringify(persons2));
var startPersons3 = JSON.parse(JSON.stringify(persons3));
var startPersons4 = JSON.parse(JSON.stringify(persons4));
.....
// Operations on persons1, persons2, persons3, persons4 which are changed in methods called here
....
// Now persons1, persons2, persons3, persons4 are modified
// Now, if I wanted persons1, persons2, persons3, persons4 to come to their original state above, ie.
// startPersons1, startPersons2, startPersons3, startPersons4, I am doing something like this
persons1 = JSON.parse(JSON.stringify(startPersons1));
persons2 = JSON.parse(JSON.stringify(startPersons2));
persons3 = JSON.parse(JSON.stringify(startPersons3));
persons4 = JSON.parse(JSON.stringify(startPersons4));
You can assume this is inside some for loop.
So, is there a better way to do this revert everytime. The number of variables can increase by lot.
if persons1, persons2 etc are inside an array, you could use map function
var persons = [/*array of persons*/]
var newpersons = persons.map(function(person) {
/*change here your person object and return it.*/
return person
})
/*here persons is the originalone, newpersone is the new version*/

How to access variables in NodeJS

I would like to understand best practice for accessing variables that are defined in an external module that would then be required in several other files.
Say we have the two following files, I would like to access the value of the h variable in consume.js
//central.js
module.exports = {
common: function() {
var h = "hello";
var b = "enabled"
}
};
and
//consume.js
var g = require('./central');
//get the value of variable h from central.js
Taking this a step further, if I have the following consume.js, fetch.js and get.js files that all imported central.js, and required a common set of variables from central.js, how does one go about defining these common variables inside central.js so that the dependent files can consume them?
Thanks!
Export:
// central.js
module.exports = {
h: "hello",
b: "enabled"
}
Import:
// consume.js
const { h, b } = require('./central')
Or alternatively:
// get.js
const central = require('./central')
// central.h
// central.b
Hope this helps!

How to use dot(.) to MongoDB(Mongoose) schema as a parameter [duplicate]

It's difficult to explain the case by words, let me give an example:
var myObj = {
'name': 'Umut',
'age' : 34
};
var prop = 'name';
var value = 'Onur';
myObj[name] = value; // This does not work
eval('myObj.' + name) = value; //Bad coding ;)
How can I set a variable property with variable value in a JavaScript object?
myObj[prop] = value;
That should work. You mixed up the name of the variable and its value. But indexing an object with strings to get at its properties works fine in JavaScript.
myObj.name=value
or
myObj['name']=value (Quotes are required)
Both of these are interchangeable.
Edit: I'm guessing you meant myObj[prop] = value, instead of myObj[name] = value. Second syntax works fine: http://jsfiddle.net/waitinforatrain/dNjvb/1/
You can get the property the same way as you set it.
foo = {
bar: "value"
}
You set the value
foo["bar"] = "baz";
To get the value
foo["bar"]
will return "baz".
You could also create something that would be similar to a value object (vo);
SomeModelClassNameVO.js;
function SomeModelClassNameVO(name,id) {
this.name = name;
this.id = id;
}
Than you can just do;
var someModelClassNameVO = new someModelClassNameVO('name',1);
console.log(someModelClassNameVO.name);
simple as this
myObj.name = value;
When you create an object myObj as you have, think of it more like a dictionary. In this case, it has two keys, name, and age.
You can access these dictionaries in two ways:
Like an array (e.g. myObj[name]); or
Like a property (e.g. myObj.name); do note that some properties are reserved, so the first method is preferred.
You should be able to access it as a property without any problems. However, to access it as an array, you'll need to treat the key like a string.
myObj["name"]
Otherwise, javascript will assume that name is a variable, and since you haven't created a variable called name, it won't be able to access the key you're expecting.
You could do the following:
var currentObj = {
name: 'Umut',
age : 34
};
var newValues = {
name: 'Onur',
}
Option 1:
currentObj = Object.assign(currentObj, newValues);
Option 2:
currentObj = {...currentObj, ...newValues};
Option 3:
Object.keys(newValues).forEach(key => {
currentObj[key] = newValues[key];
});

Sharing & modifying a variable between multiple files node.js

main.js
var count = 1;
// psuedocode
// if (words typed begins with #add)
require('./add.js');
// if (words typed begins with #remove)
require('./remove.js');
// if (words typed begins with #total)
require('./total.js');
module.exports.count = count;
total.js
var count = require('./main.js').count;
console.log(count);
add.js
var count = require('./main.js').count;
count += 10;
console.log(count);
remove.js
var count = require('./main.js').count;
count -= 10;
console.log(count);
console.log
1
11
-9
Background:
I have an application (irc bot), and I want to add a feature that peeps can do #add 1 or #remove 1. I have a main.js that then requires different files depending on the triggers that are said. So add would trigger the add.js file, and that would then require('main.js') and add 10 (10 for simplification, it'll actually parse the number and use that number) to it. The problem I'm having is when someone goes about and does #remove. It require('main.js') and subtracts 10 from 1 resulting in -9. And doing #total would output 1.
I've done a fairly good search for module.exports and I haven't come across an example like the one i listed above. The docs don't include any examples close to what I'm wanting to do; and these questions 1, 2 I understand--but aren't of any usefulness to me--as I understand what's being said there.
Question:
I'd like to have both #add and #remove manipulate the same variable ( count ), and for #total to return the total of count with the #add and #removes taken into account. Am I using module.exports incorrectly; or is there a common way that variables are shared, with one file being able to modify the contents of the module.exports and returning the results to the main.js file?
Your problem is that when you do var count = require('./main.js').count;, you get a copy of that number, not a reference. Changing count does not change the "source".
However, you should have the files export functions. Requiring a file will only run it the first time, but after that it's cached and does not re-run. see docs
Suggestion #1:
// main.js
var count = 1;
var add = require('./add.js');
count = add(count);
// add.js
module.exports = function add(count) {
return count+10;
}
#2:
var count = 1;
var add = function() {
count += 10;
}
add();
#3: Personally i would create a counter module (this is a single instance, but you can easily make it a "class"):
// main.js
var counter = require('./counter.js');
counter.add();
console.log(counter.count);
// counter.js
var Counter = module.exports = {
count: 1,
add: function() {
Counter.count += 10;
},
remove: function() {
Counter.count += 10;
}
}
Not sure if this new or not but you can indeed share variables between files as such:
main.js
exports.main = {
facebook: null
};
counter.js
var jamie = require('./main');
console.info(jamie); //{facebook: null}
jamie.main.facebook = false;
console.info(jamie); //{facebook: false}
anothercheck.js
var jamie = require('./main');
console.info(jamie); //{facebook: null} //values aren't updated when importing from the same file.
jamie.main.facebook = true;
console.info(jamie); //{facebook: true}
Now you can share between files.
I know I'm a little bit late to answer this questions, just 7yrs!
You can simply use a global variable:
global.myVar = 'my-val';
console.log(myVar); // returns 'my-val'
// from here on it's accessable to all modules by just the variable name
using-global-variables-in-node-js
I have same problem like you,.. Sometimes I'd like to sharing variables between multiple files because I love modular style eg. separating controller, function, models in different folders/files on my node.js script so I can easy manage the code.
I don't know if this is the best solution but I hope will suit your needs.
models/data.js
// exports empty array
module.exports = [];
controllers/somecontroller.js
var myVar = require('../models/data');
myVar.push({name: 'Alex', age: 20});
console.log(myVar);
// [{ name: 'Alex', age: 20 }]
controllers/anotherController.js
var myVar = require('../models/data');
console.log(myVar);
// This array has value set from somecontroller.js before...
// [{ name: 'Alex', age: 20 }]
// Put new value to array
myVar.push({name: 'John', age: 17});
console.log(myVar);
// Value will be added to an array
// [{ name: 'Alex', age: 20 }, { name: 'John', age: 17}]
There is no way you can share a reference between different files. You shouldn't be.
I have a main.js that then requires different files depending on the triggers that are said
I don't think that's a good idea. All require statements you'll ever need must be at the top of the file.
I also see that You're requiring main.js in total.js and total.js in main.js. The require() function imports the module.exports of the file and assigns it to the namespace you provide. Your code shouldn't be split into files this way. You extract code into separate files only when they're modules by themselves. And if you do, you wouldn't be importing 2 files on each other.
It is also good to note that in javascript, when you assign something to a namespace, It gets copied (cloned) if it's a primitive. If it's an object, both namespaces then refer to the same object
var num = 5;
var prim = num;
prim++; // prim is 6, but num is still 5.
var num = {five:5};
var ob = num;
ob.five = 6;
console.log(num.five) //also 6.
A little hack that works but isn't recommended is using the process variable. You can apply different properties to it and essentially use them like you would the window object in browser-based JS. This little hack will provide a reference to the variable. It can be changed and manipulated and the change will carry over to all files that are required.
But do note that it is not recommended as overriding the process variable could have some unexpected effects and is subject to loss of information should another process interfere.
file1.js:
const s1 = require('./file2');
process.num = 2;
console.log("file1", process.num);
s1.changeNum();
console.log("file1", process.num);
file2.js:
module.exports.changeNum = () => {
process.num = 3;
console.log("file2", process.num);
};
output:
file1 2
file2 3
file1 3
alternatively, to all other answers
getters & setters
var _variableThing = 1223
module.exports = {
get variableThing(){
return _variableThing
},
set variableThing(val){
_variableThing = val
}
}
won't work with direct imports though

Resources