My app.js contains:
var m1 = require("./m1");
m1.f1(...);
My m1.js contains:
var m1 = module.exports = {};
m1.f1 = function(...) { };
I would like to pass somevariable when loading m1 from app.js:
var m1 = require("./m1")(somevariable);
How can I write m1.js so that the function definition of m1.f1 can access somevariable?
If you want to be able to do this:
var m1 = require("./m1")(somevariable); // it is equivalent to var m = require("./m1"); and then m(someVariable); so m (the exports of the module m1.js) should be a function
then module.exports in m1.js should be a function:
// m1.js:
module.exports = function(theVariable) {
// use variable then return the following object:
return {
f1: function() { /* ... */ }
};
}
So now you can use the module in app.js like this:
// app.js:
var m1 = require("./m1")(someVariable);
m1.f1(/* ... */);
module.exports is the value that will be returned by the call to require when loading the module.
// app.js
require("./m1")(somevar);
// m1.js
module.exports = function(param) {
return "something";
}
The answer above by Ibrahim makes sense if you want to call m1 as a function. What it seems to me, though, is that your use case would be better served by using a JS class.
That way, you can import 'm1' the regular way with require('m1') and then create an instance of M1 with new m1(<whatever you want to pass in>);
Now when you want to call M1, just use m1.f1()
To support classes, your M1 should look something like:
export default class m1 {
constructor(param1, param2) {
this.param1 = param1;
this.param2 = param2;
}
f1() {
do whatever with params here
}
}
The biggest benefit of this is readability. Now when someone (or you) looks at your code, they will see where this input is coming from. Otherwise, it can be hard to track down where the params are coming from. Especially as your code gets more complex.
Related
I'm learning reveal module pattern, and I'm trying to create a reusable function. (In my project, the function will make the page scroll. I don't think it's necessary to post the whole code here. I'm just putting the concept.)
The basic overview is, there's a function that will not return anything. There's no need for public variables. Here's the code. The questions are at the comments in the code:
JSFiddle
var MyModule = (function() {
// Is this the correct place to insert the
// variables that will be used throughout 'MyModule'?
var foo = 'foo',
foo2 = 'foo2',
param1 = null;
var MyModule = function(_param1) {
param1 = _param1;
logParam();
};
function init() {
foo = 'something';
}
function logParam() {
console.log(param1);
}
init();
return MyModule;
})();
var module = new MyModule('Some Paramater');
// Is this okay? Does it still follow reveal module pattern?
MyModule('Some Other Paramater');
// Or do I always have to do like this:
var module = new MyModule('Some Paramater');
The Module Reveal Pattern provides both private and public encapsulation.
Below an example with some explanatory comments.
More info about JavaScript pattern included Module Reveal Pattern can be found here
var myRevealingModule = (function () {
// below are private variables and functions that are not accessible outside the module this is possible thanks to a javascript closure
var privateVar = "Ben Cherry",
publicVar = "Hey there!";
function privateFunction() {
console.log( "Name:" + privateVar );
}
// below are public functions, they will be publicly available as they are referenced in the return statement below
function publicSetName( strName ) {
privateVar = strName;
}
function publicGetName() {
privateFunction();
}
// Reveal public pointers to
// private functions and properties
return {
setName: publicSetName,
greeting: publicVar,
getName: publicGetName
};
})();
myRevealingModule.setName( "Paul Kinlan" );
console.log(myRevealingModule.greeting);// public
console.log(myRevealingModule.getName());// public
//console.log(myRevealingModule.privateFunction());// private, you cannot access it
Answering your comments:
// Is this okay? Does it still follow reveal module pattern?
MyModule('Some Other Paramater');
Yes, it's OK. If you want that your reveal module pattern "MyModule" must be selfclosing:
var MyModule = function(param1) {
var myPlublicFunction = function(){
}
return {
myPlublicFunction: myPlublicFunction
};
}(); //selfclosing
OR
// Or do I always have to do like this:
var module = new MyModule('Some Paramater');
If you want that, your reveal module pattern "MyModule" must be not selfclosing:
var MyModule = function(param1) {
var myPlublicFunction = function(){
}
return {
myPlublicFunction: myPlublicFunction
};
}; // not selfclosing
I hope it helps
I have a module like below
'use strict';
var val = GlobalVariable.someMethod();
...
...
module.exports = myExportedClass;
I am calling it with require('./myModule');. But would like to know if GlobalVariable can be dynamically injected.
I have tried this method, though I know that this does not work :)
(function(GlobalVariable) {
require('./myModule');
})(SomeOtherGlobalVariable);
So it did not, because module will execute in different scope. Is there any other way where I can pass my own version of GlobalVariable when using require.
Yes, it can be injected. Do something like the following:
module.exports = function(injectedObject) {
return {
doSomething: function() {
return injectedObject.something();
}
}
};
you can pass you variable as an argument when requiring it
yourvariable="value";
var file = require('./myModule')(yourvariable);
or can pass it separately, as file now contain function reference of module.exports
yourvariable="value";
var file = require('./myModule');
file(yourvariable)
your module will look like as:
module.exports = function(yourVaraible) {
yourVaraible.myfunction = function() {
};
return yourvariable;
};
I have two different js files that use the same module.
file1.js:
var mod1 = require('commonmodule.js');
mod1.init('one');
file2.js:
var mod2 = require('commonmodule.js');
mod2.init('two');
(both these files file1.js, file2.js are loaded inside my server.js file, they themselves are modules)
now in commonmodule.js:
var savedName;
exports.init = function(name)
{
savedName = name;
}
exports.getName = function()
{
return savedName;
}
I noticed that this savedName is always overridden dependent on who set it last.So it doesn't seem to work. How would I get a module to maintain state?
Note: I also tried to set savedName as exports.savedName in the commonmodule.js but it doesn't work either
You can just create a new instance every time the module is required:
commonmodule.js
function CommonModule() {
var savedName;
return {
init: function(name) {
savedName = name;
},
getName: function() {
return savedName;
}
};
}
module.exports = CommonModule;
file1.js
var mod1 = new require('./commonmodule')();
mod1.init('one');
console.log(mod1.getName()); // one
file2.js
var mod2 = new require('./commonmodule')()
mod2.init('two');
console.log(mod2.getName()); // two
modules in and of themselves are simple object instances. A single instance will be shared by all other modules (with the caveat that it is loaded via the same path). If you want state, use a class and export a constructor function.
example:
//Person.js
function Person(name) {
this.name = name;
}
module.exports = Person;
To use it:
var Person = require("./Person");
var bob = new Person("Bob");
Modules are not like classes/class functions; by default, mod1 and mod2 will refer to the same module due to caching. To keep track of per-instance state, you'll need a constructor function or something similar inside your module, e.g.
var mod = require('commonmodule.js');
var state = new mod.init('one');
Where init defines the stateful object. You could also have it return an object literal, in which case you wouldn't have to use new (e.g. var state = require('commonmodule.js').init('one');)
(This is assuming you want the module to have other, shared state in addition to the per-instance state; if that is not the case, Peter Lyons' method would be simpler.)
You could perhaps remove from cache your module. Like that:
file1.js:
var mod1 = require('commonmodule.js');
mod1.init('one');
file2.js:
delete require.cache[require.resolve(modulename)];
var mod2 = require('commonmodule.js');
mod2.init('two');
But I don't find it very convenient and clean.
But you could also clone it or make a small proxy.
Also you could create classes:
var savedName;
exports.obj = {}
exports.obj.prototype.init = function(name)
{
savedName = name;
}
exports.obj.prototype.getName = function()
{
return savedName;
}
Then :
var mod2 = new (require('commonmodule.js'))();
mod2.init('two');
Currently, I write node.js modules like this:
//MyModule.js
function MyModule() {
...somecode
}
MyModule.prototype.someFunc = function() {...}
module.exports = MyModule
However, when I need to use the module, I have to write something like this:
//main.js
var MyModule = require('MyModule');
var myModule = new MyModule();
This seems terribly ugly. Isn't there some way to do something like this
//main.js
var myModule = require('MyModule').new();
Am I doing something wrong?
quick hack for something not ugly
module.js
function MyModule() {
console.dir('constructor');
}
module.exports = MyModule;
app.js
Function.prototype.new = function () {
return new this();
};
var MyModule = require('./module.js').new(); // 'constructor'
If your module consists solely of functions, it may not need to be created as an instance - just define your module as being an object filled with functions. Like so:
var MyModule = {
prepareHtmlContent: function() {
},
autoLoadActionInitiatorFunctions: function() {
}
};
The reason I suggest this is that you've referred to your object as 'MyModule'. If your intent is specifically to use it as a 'Class', and instantiate separate copies of it when they're needed, then you're doing it the correct way.
Here is what I use
(function(module) {
module.myFunction = function() {
}
module.createSomeObj = function() {
return {
foo: 1,
bar: 'bar'
};
}
}(module.exports));
Usage
var myModule = require('./myModule');
myModule.myFunction();
var myObject = myModule.createSomeObj();
//lib.js
var opt = 0
exports.set = function(arg) {
opt = arg
}
exports.prn = function() {
console.log(opt)
}
///prog.js
var lib = require('./lib')
var lib2 = require('./lib')
lib.set(222)
lib2.set(333)
lib.prn()
lib2.prn()
prog.js will output:
333
333
but I need it to output:
222
333
In ohter words, opt must be unique to variable lib and to variable lib2. How to achieve that?
That's because normally nodejs caches its modules which are got via require. You may use the following helper:
// RequireUncached.js
module.exports = function(module) {
delete require.cache[require.resolve(module)]
return require(module);
}
and the usage of the helper:
var requireUncached = require('RequireUncached.js');
requireUncached("./lib");
Have in mind that this approach is considered as bad practice and should not be used. I'll suggest to wrap your logic into a function, require the module and call the function. So, every time you get a new instance.
require will not load scripts multiple times, but always yield the same instance.
If you need different environments, make your module a constructor function that allows to be instantiated multiple times. Store opt on each object for that instead of in the (global) module scope.
// lib.js
module.exports = function constr() {
var opt = 0
this.set = function(arg) {
opt = arg
};
this.print = function() {
console.log(opt)
};
};
// prog.js
var lib = require('./lib'),
inst1 = new lib(),
inst2 = new lib();
/* or short:
var inst1 = new require('./lib')(),
inst2 = new require('./lib')(); */
inst1.set(222)
inst2.set(333)
inst1.print()
inst2.print()
The way the NodeJS module system works, the output is correct and your expectations contradict the design principle here.
Each module is loaded once and only once, and subsequent calls to require simply return the reference to the pre-existing module.
Maybe what you need to do is create a class you can create one or more instances of instead of using module-level globals.
Adding to Bergi's answer, You may also try it like
// prog.js
var lib = require('./lib')(),
lib2 = require('./lib')();
lib.set(222)
lib2.set(333)
lib.print()
lib2.print()
// lib.js
module.exports = function constr() {
var opt = 0
return { set : function(arg) {
opt = arg
},
print : function() {
console.log(opt)
}
}
};
Add this line as first line of your lib.js
delete require.cache[__filename]
now your module becomes in a separate namespace each time you require it.