How can a module in node.js maintain state? - javascript

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');

Related

How may I split my JavaScript classes across multiple files and yet have them belong to the same namespace?

I learnt that you could mimic namespaces in JavaScript by scoping your classes / objects inside a function expression or an object literal. That way the containing object or function provides a namespace and scope for the contained.
But for those to work, all the contained objects have to be within the same file, right?
Because if I had two namespace / naming container objects with the same name in two different files, they would overwrite each other depending on the order in which I included the source files.
File1.js
var Automtomobiles =
{
function Wheel() { ... }
};
File2.js
var Automtomobiles =
{
function Car() { ... }
};
How do I span objects / class definitions across multiple files but keep them within a same namespace?
Make Automtomobiles as global object
File1.js
var Automtomobiles = Automtomobiles || {};
Automtomobiles.wheel = function() {
}
File2.js
var Automtomobiles = Automtomobiles || {};
Automtomobiles.car = function() {
}
To make them global you can use window.Automtobiles = function() or to define an static property to a type. You can use .prototype
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
console.log(new Person("john", "smith", 20, "red"));
Note how "English" is attached to each instance of Person after using the Prototype function
For your particular case, you can define Automtobiles then prototype it..
function Automtomobiles() {
};
Automtomobiles.prototype.wheel = function() { ... }
Automtomobiles.prototype.car = function() { ... }
Using pure javascript you could use the common notation that lot of libraries use. For one file:
var Automtomobiles;
(function (Automtomobiles) {
var Wheel = (function () {
function Wheel() {};
return Wheel;
}());
Automtomobiles.Wheel = Wheel;
})(Automtomobiles || (Automtomobiles = {}));
And the other file:
var Automtomobiles;
(function (Automtomobiles) {
var Car= (function () {
function Car() {};
return Car;
}());
Automtomobiles.Car= Car;
})(Automtomobiles || (Automtomobiles = {}));
Anyway, if you are open to use third party libraries, they could help you too. Long time ago I used Dojo declare feature, which manages the namespaces and class names for you, althoug I'm sure that at current exists more libraries to reach that.
In fact, you also could use Typescript, which is perfect to reach your goal and vey use to learn. The code generated by Typescript looks like the examples I posted above.

JavaScript function prototype calling parent from child

I have a stupid reference problem
I declared a namespace variable called MYAPP
var MYAPP = MYAPP || function() {
this.name = 'My Application';
this.someImportantID = 123;
};
And then I wanted to sperate my code in namespaces/functions and so I did
MYAPP.prototype.homepage = function() {
urls: {
linkOne: '/link/to/some/page/',
linkTwo: '/link/to/some/page/'
},
doSomething: function() {
// ajax call
$getting = $.get(this.urls.linkOne)
// and so on .....
// how can I acces someImportantID ??
}
}
then i use it like this
app = new MYAPP();
app.homepage.doSomething();
but how can I access someImportantID within the function doSomething()
Get rid of this .homepage stuff. Why are you doing that anyway?
This is something of a constructor pattern. Declare your constructor:
var MYAPP = function(URLCollection) {
this._name = 'My Application';
this._someImportantID = 123;
this._URLCollection = URLCollection;
}
Then declare the instance methods:
MYAPP.prototype = {
doSomething: function() {
// ajax call
$getting = $.get(this._URLCollection.linkOne);
// and so on .....
// how can I acces someImportantID ??
}
}
Then declare your instance passing in your collection of links:
var lCollection = { linkOne: 'URL', linkTwo: 'URL' };
var myHomePage = new MYAPP(lCollection);
You can access doSomething from the instance:
myHomePage.doSomething();
You can get to some important ID from the instance also:
myHomePage._someImportantId;
Or from within the instance, by:
this._someImportantId;
This is rough - it should point you in the right direction.
If there are multiple MyApp instances then you can do the following:
//IIFE creating it's own scope, HomePage constructor
// is no longer globally available
;(function(){
var HomePage = function(urls,app){
this.urls=urls;
this.app=app;
}
HomePage.prototype.doSomething=function(){
console.log('urls:',this.urls,'app:',this.app);
}
//assuming window is the global
window.MyApp = function(urls){
this.name='app name';
this.homePage=new HomePage(urls,this);
}
}());
var app = new MyApp(['url one','url two']);
app.homePage.doSomething();
If you only have one app and that app only has one homePage object you can do it the following way as well:
var app = {
name:'app name'
,homePage:{
urls:['url one','url two']
,doSomething:function(){
console.log('urls:',this.urls,'app:',app);
//or
console.log('urls:',app.homePage.urls,'app:',app);
}
}
}
app.homePage.doSomething();
More on constructor functions, prototype and the value of this here.

How do you use class based OOP JavaScript in the browser?

I've been converting my procedural JS functions into a class and now I'd like to know when to instantiate it.
Here is my class:
MyProject = function() {};
MyProject.prototype.myProperty = "10";
MyProject.prototype.myMethod = function (value) {
// do something
}
Here is my HTML page:
<script src="javascriptfilesdirectory/MyProject.js"/>
<script>
function initialize() {
myProject = new MyProject();
}
</script>
<body onload="initialize()" >
My question is do I intialize it on page load and create a local variable as shown above or do I initialize it in the JS class file?
Here is my JS file:
MyProject = function() {};
MyProject.prototype.myProperty = "10";
MyProject.prototype.myMethod = function (value) {
// do something
}
myProject = new MyProject();
Also, I'm talking in general and in this case it's a singleton. I only want one copy of it in use.
If you really want it as a singleton, you can do it easier than that, something like:
var myProject = new (function() {
this.myProperty = "10";
this.myMethod = function(value) { }
})();
Your "class" is only defined long enough to assign it once, since you're never going to instantiate a second copy.
For a non-singleton, I tend to follow the pattern found on the TypeScript page:
var Greeter = (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
})();
var greeter = new Greeter("world");
Also, I'm talking in general and in this case it's a singleton. I only want one copy of it in use.
In that case, just directly create the object:
var myProject = {
myProperty: "10",
myMethod: function() { ... }
};
When and where you create the object doesn't matter, as long as you have access to it when and where you need it.

Node.js double call to require()

//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.

Node.js prototypal inheritance with require

I have a problem with inheritance of two functions in node.js when i use require functions.
Here is my case:
function administrators () {
this.user = 'bob';
}
administrators.prototype.print_user = function () {
console.log(this.user);
}
/*******/
function helper() {}
helper.prototype = new administrators();
helper.prototype.change_administrator = function() {
this.user = 'john';
}
var h = new helper();
h.print_user();
h.change_administrator();
h.print_user();
As you can see here I have two functions:
administrations just has user variable and print_user function.
helpers inherits everything from administrators and then we add change_administrator which changes this.use declared in administrators().
Here is the question:
I want to have this functions (administrators and helper) in separated files, for example: administrators.js and helper.js.
Then I want to include these two files in index.js with require, and inherit administrators variables and functions to helper like I did in the example above.
P.S. I was looking for similar questions but there is nothing about that kind of inheritance.
You need to require administrators from within the helpers.js file.
administrators.js
function administrators () {
this.user = 'bob';
}
administrators.prototype.print_user = function () {
console.log(this.user);
}
module.exports = administrators;
helpers.js
var administrators = require('./administrators');
function helper() {}
helper.prototype = new administrators();
helper.prototype.change_administrator = function() {
this.user = 'john';
};
module.exports = helper;
index.js
var helper = require('./helpers');
var h = new helper();
h.print_user();
h.change_administrator();
h.print_user();
You would have to manually extend them in the class that did the requiring.
Extend here meaning "copy the methods and properties from one object to the other"
alternately have helpers require administrator directly

Categories

Resources