How to modify variables from another file in node.js - javascript

I'm currently working with the discord.js library.
I guess I can call it by this name, but whenever I want to access a file, this doesn't work.
Let's say I have a file called calc.js and I want to access the main.js file and take a variable out of there using exports and require it to just take the value out of it.
But I haven't found even one way online to modify the variables and return another value to the file.
Can someone help me?

As noted, JavaScript doesn't pass every variable by reference. If you need to access a primitive value like a number, you could declare it as a local variable and export functions to access and modify it. Something like this rough example:
increment.js
let count = 0;
module.exports = {
get: () => count,
increment: () => ++count
};
main.js
const { get, increment } = require('./increment.js');
console.log(get());
console.log(increment());
console.log(get());
Edit: You should probably not name your accessor get, as that's the key word used to describe getters in ES6. Or better yet, turn such a get function into a getter with a more suitable name.

Related

How do you call a function inside a module.exports = function () in another class?

In the following example, simply putting module.exports = {save} on the jsFileName.js file functions is not an option here, due to limitations on my codebase. Is this possible to access the function from the export, inside of callFunctionFromAboveFile.js shown below? See the below example of how I'd like to access that function. I've searched all the other answers to questions similar but they all mention using the exports differently as I stated in my first line above.
If there is a way to access it as it is shown, please share your answer or details as to why it's not possible. Also, other ways to handle this would be helpful but I can't change the class up much given the limitation to the codebase.
jsFileName.js
module.exports = function (JsFileName) {
JsFileName.save = function (stuff) {}
}
callFunctionFromAboveFile.js
const JsFileName = require('jsFileName');
// TODO I'm not sure how this would call the save() w/out using exports differently.
// TODO I have to use exports as I've posted it in jsFileName.js
The default export of jsFileName.js is a function that adds functions to its parameter JsFileName.
Apparently, you can pass any object which is then modified to act as the module's exports.
That means: Pass any object you want to have the modules' functionality. Note that the object is not returned, so you have to keep the reference to it yourself.
// callFunctionFromAboveFile.js
const JsFileName = {};
require("jsFileName") // Get default export (the function)
(JsFileName); // Call with any object you want to "enhance"
JsFileName.save(/*...*/);

Allow modules access to functions/variables defined in server that requires them?

Here's a basic example of what I'm trying to do:
ModuleA.js
module.exports = {
doX () {
console.log(data['a']);
}
}
ModuleB.js
module.exports = {
doX () {
console.log(data['b']);
}
}
server.js
let data = { a:'foo', b:'bar' };
let doX = {};
doX['a'] = require('./ModuleA.js').doX;
doX['b'] = require('./ModuleB.js').doX;
doX['a'](); // Should print 'foo'
doX['b'](); // Should print 'bar'
In the actual implementation there would be many more variables to pass in than just data, so passing that to the functions isn't a viable solution.
This almost works, but the functions in the modules need access to functions and variables at the top level of the server file. I know I could global.variable all of my variables and functions but I'd rather not, as I've only seen people recommend against that. Of course I could pass every single variable and function in each function call, but that would look ridiculous and brings up way too many potential problems. I was hoping I could pass a reference to the server's namespace, by passing this or something, but that didn't work. I could register every function and variable on some object and pass that around, but that's inconvenient and I'm trying to refactor for convenience and organization. I think I could read in the module files and eval them, as seen here, but I would much rather use the standard module.exports system if possible.
I'll summarize my comments into an answer.
Your data variable is local to server.js and is not accessible to your other two modules. I'd suggest you pass it to them when you load those modules as a means of sharing it with them. That design pattern is typically called a "module constructor" if you want to read more about it.
Passing data from one module to another is how you achieve shared data with separate modules without using globals. That's how you do it. Since you've now rejected the usual design pattern, there's not much else we can do without understanding a lot more about the real problem so we can go further outside your box and suggest a better design than the path you're down.
Abstracting hardware to have a common set of methods sounds like a perfect fit for subclasses where each piece of hardware has its own subclass, all with the same interface. Shared data could be in the base class.
You can pass a lot of variables at once if you make them properties of an object and pass just the object. Then, both places can reference the same properties on the same object and you can pass an infinite number of properties by passing one object. There is no way to pass a modules namespace. You have to create your own object with properties on it and pass that. You can create such an object and then set that object into the base class and then all your derived classes can have access to that object.
In short:
module.exports = {
doX () {
console.log(data['a']);
^^^^ this variable is not available here. You should pass it as argument to make it available.
}
}

Using IIFEs in JS for protecting data by creating private variables

I have created a small program to print some message in the console when a button in the DOM is clicked.
Code-
<!DOCTYPE html>
<html>
<body>
<button onClick="printName()">Click</button>
</body>
<script>
const personDetails = (function() {
let name = 'john';
function displayMsg() {
console.log(name);
}
return {
displayName: displayMsg
}
})();
function printName() {
personDetails.displayName();
}
</script>
</html>
In above code, to protect name, I am using IIFE and returning a method displayName inside personDetails. On click of button, printName is executed which further executes personDetails.displayName. Here are my concerns -
Is this the right way to use IIFEs to protect the data? If no, then please provide a solution. This is getting confusing everyday.
Even if we are keeping only 1 global variables, other exposed
variables are accessible through the global one like displayName
method.
Let's say I have successfully protected the data, still I am able to
change the function definition in the console through
personDetails.displayName which should be avoided.
Old method:
function displayMsg() { console.log(name); }
New method:
personDetails.displayName = function() { console.log('Hiiii'); }
Welcome to StackOverflow. Please take the tour and visit the help center.
1. Is this the right way?
There is at least one 'close' vote for this question being primarily opinion-based. That voter is correct that this portion of the question is hard to answer definitively.
So let me just say that this is at least one appropriate way to do this. There are many others. You could simplify this, if you like, to
const personDetails = (function() {
let name = 'john';
return {
displayName: function() {
console.log(name);
}
}
})()
And you could simplify it still more by using arrow functions.
2. Why are other variables still exposed?
That is the point of such code: to create a public interface that makes reference to some private data. You could also skip personDetails and expose only displayName by returning the function and not an object with that function as a property.
But if you want to be able to use that data, then you need at least some public interface!
3. How is it that this function reference can still be changed?
There are techniques that would allow you to protect this variable from change. But then, perhaps, a user will redefine personDetails to be something else. Could you protect this? Maybe. But then what's to stop someone from intercepting your Javascript before it's interpreted by the browser, altering these definitions?
The point is that you will only ever have so much control. If you don't trust users, you shouldn't be shipping them code... which means you shouldn't be writing for the web.
Using IIFEs to protect data from accidental changes, or even well-meaning but dangerous intentional changes, is fine. Trying to pretend that you're entirely in charge of the code once it leaves your hands is folly however.
Yes
Yes, but there is only one global variable. This massively reduces the risk of other code accidentally overwriting it.
Yes. You can't stop deliberate modification to code once it has left your control and arrived at the client.
Minimising use of globals is a strategy to reduce the likelihood of bugs caused by other code. It isn't a form of DRM.
Let's say I have successfully protected the data, still I am able to
change the function definition in the console through
personDetails.displayName which should be avoided.
This can be avoided by changing the value of the writable property of the returned object.
Modify the function assignment of personDetails as follows:
"use strict";
const personDetails = (function() {
let name = 'john';
function displayMsg() {
console.log(name);
}
var obj = {};
Object.defineProperty(obj, 'displayName', {
value: displayMsg,
writable: false
});
return obj;
})();
Now, if anyone tries to overwrite the property value,
function printName() {
personDetails.displayName = 10;
}
printName();
you get an error like this:
Uncaught TypeError: Cannot assign to read only property 'displayName' of object '#<Object>'
at printName (<anonymous>:17:35)
Check out this writeup for more details.
Note: This will throw an error only in strict mode and silently reject any change otherwise.

What is the better practice for sharing variables across Node.js modules

So I'm writing a multiplayer game with Socket.io and most of the socket calls are handled in the main file (app.js) including storing usernames and the sockets they're connected to.
But I'd like to create a separate file (game.js) that handles all the game code including socket emissions to certain rooms. However to do that I'll need access to my array with the users/sockets stored in it (which is in app.js)
So I'm wondering what the best way to share the variable would be? Should I pass the the array reference through every function that I need it in?
Or should I write a function that is called once and creates a global variable (or the scope that I need it in) with a reference to the array?
Also If I should ever need to share the same dependency across multiple files should I call require in each one of them?
About Modules and the use Global/Shared State
An interesting aspect of modules is the way they are evaluated. The module is evaluated the first time it is required and then it is cached. This means that after it has been evaluated no matter how many times we require it again, we will always get the same exported object back.
This means that, although Node provides a global object, it is probably better to use modules to store shared stated instead of putting it directly into the global object. For instance, the following module exposes the configuration of a Mongo database.
//module config.js
dbConfig = {
url:'mongodb://foo',
user: 'anakin',
password: '*******'
}
module. exports = dbConfig;
We can easily share this module with as many other modules as we want, and every one of them will get the same instance of the configuration object since the module is evaluated only once, and the exported object is cached thereon.
//foo.js
var dbConfig1 = require('./config');
var dbConfig2 = require('./config');
var assert = require('assert');
assert(dbConfig1==dbConfi2);
So, for your specific problem, the shared state that you want to share can reside in a singleton object exposed by whatever module you have. Just make sure your singleton object is the one being exposed in your module and you will always get a reference back to it every time you require it.
If by 'variable' you mean reference to the socket - you may want to consider passing a callback or module to game.js which handles the emission - but that game.js calls when necessary.
Like Edwin Dalorzo mentioned, having a separate file for all your variables seems the best.
I've had a similar problem for a few hours now because I didn't know that variables were persistent. The scenario that I had was:
I have two files cli.ts and main-lib.ts. cli.ts reads user input, and depending on the input, runs functions in main-lib.ts. While main-lib.ts is busy validating the input, cli.ts uses some global variables that main-lib.ts generates when a test passes. The only limitation is that I can't mix the main-lib.ts code with the cli.ts, I can only share the function callValidateFunction.
The issue that I had originally thought of was: if I were to make a global-vars.ts file, the variables' data will still be different for each call of require (i.e., calling setVar(...) will only change the variable value that was imported.
However, thanks to Edwin's answer, I managed to implement a bridge:
// cli.ts
import { setVar, getVar } from "./var-bridge";
import { callValidateFunction } from "./main-lib";
function run(args: string[]): void {
// ...
if (arg == "--email") {
// Set the test status.
setVar("testStatus", "pending");
// Validate the input email address.
callValidateFunction("validateEmail", nextArg());
// Get the testStatus.
const testStatus: string = getVar("testStatus");
}
// ...
}
// main-lib.ts
import { setVar, getVar } from "./var-bridge";
const funcs: {name: string, func: (arg: string) => boolean} = {};
funcs.validateEmail = function(arg: string): boolean {
let passed: boolean = false;
// ...
return passed;
};
function callValidateFunction(functionName: string, arg: string): void {
// ...
const passed = funcs[functionName](arg);
if (passed) setVar("testStatus", "passed");
}
// ...
// var-bridge.ts
const variables: {name: string, value: any} = {
"testStatus": "",
// ...
};
function setVar(varName: string, varValue: any): void {
variables[varName] = varValue;
}
function getVar(varName: string): any {
return variables[varName];
}
export { setVar, getVar };

'variable' : function(req, res){} means?

I am currently starting with node.js, so I am for the first time using Js beyond dom manipulation.
I came across a code piece like below. I cant understand it. What is happening? is it a key value object? Is an anonymous function being passed to 'new'?
module.exports = {
'new': function(req, res) {
res.view();
},
/**
* Overrides for the settings in `config/controllers.js`
* (specific to UserController)
*/
_config: {}
};
As others have said, this is ultimately just creating an object called module.exports then assigning two properties to it. One is another object called _config and the other is a function called new that expects two arguments.
That's the plain JavaScript explanation.
In node.js, you're also seeing a few conventions in play, which I'll describe below.
One convention is module.exports.
This is the object that will be made available when some other code loads this file using require(). It would work something like this:
var m = require('yourmodule.js');
m.new(req, res);
Another convention is the pair of arguments: req, res.
These are usually parameters that represent a request (like an http.IncomingMessage) and a response (like a http.ServerResponse).
Putting it all together, this module is probably defining a Controller that will receive http requests, and render them as responses. It currently does this for new, and there are probably routes configured elsewhere that call this method when a user requests something like 'http://server.come/user/new'.
Looks like basic JavaScript.
An object named module has a property named exports that is an object.
This object has a property named new whose value is an anonymous function.
In theory you could invoke the method like this:
module.exports.new(someRequest, someResponse);

Categories

Resources