I have a custom module and would like to provide a method to initialize it on first require, but directly return an object on subsequent requires.
But the module gets cached when first required and therefore subsequent requires still return the init function instead of returning obj directly.
server.js:
var module = require('./module.js');
var obj = module.init();
console.log('--DEBUG: server.js:', obj); // <-- Works: returns `obj`.
require('./other.js');
other.js:
var obj = require('./module.js');
console.log('--DEBUG: other.js:', obj); // <-- Problem: still returns `init` function.
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = (obj) ? obj : { init: init };
How can I work around that problem? Or is there an established pattern for achieving such?
But I would like to keep obj cached, because my real init does some work I would rather not do on every require.
There are some ways to clear the require cache. You may check here node.js require() cache - possible to invalidate?
However, I think that this is not a good idea. I'll suggest to pass the module which you need. I.e. initialize it only once and distribute it to the other modules.
server.js:
var module = require('./module.js');
var obj = module.init();
require('./other.js')(obj);
other.js:
module.exports = function(obj) {
console.log('--DEBUG: other.js:', obj); // <-- The same obj
}
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = { init: init };
Related
If I want to use an object and its methods in another file, how would I set up my module.exports?
Object:
var Object = function ()
{
...
}
Object.prototype.foo = function (param)
{
...
}
Module.export:
module.exports = {
Object : Object
}
or
module.exports = {
Object : Object,
foo : Object.prototype.foo
}
?
A few ways of doing this but if you're trying to access prototype methods from your other file, then you'll need to instantiate your constructor,
something like:
For ex:
// lib.js
var YourThing = function () {
}
YourThing.prototype.someMethod = function () {
console.log('do something cool');
}
module.exports = YourThing;
// index.js
var YT = require('./lib.js');
var yourThing = new YT();
yourThing.someMethod();
module.exports = Object;
This will export your Object as a Module.
If your object is not renewed in your app, the best way to use it as an executed function with late binding of its prototype methods
const _ = require('lodash')
var Object = function ()
{
..
_.bindAll(this); // at last bind all methods. this way you won't miss a method
}
Object.prototype.foo = function (param)
{
...
}
module.exports = new Object();
then you can call the functions like,
const myObj = require('./object-file')
myObj.myMethod();
If you need reusable component,
module.exports = Object;
const _obj = require('./object-file'); // you can call this way anywhere in any function and for every require, it creates a new object.
var object = new _obj();
_obj.anyMethod();
I'm running into a really frustrating problem in Node.js.
I'll start with what I'm doing.
I'm creating an object in a file and then exporting the constructor and creating it in other files.
My objects are defined like so:
File 1:
var Parent = function() {};
Parent.prototype = {
C: function () { ... }
}
module.exports = Parent;
File 2:
var Parent = require('foo.js'),
util = require('util'),
Obj = function(){ this.bar = 'bar' };
util.inherits(Obj, Parent);
Obj.prototype.A = function(){ ... };
Obj.prototype.B = function(){ ... };
module.exports = Obj;
I'm trying to use the object like so in another file
File 3:
var Obj = require('../obj.js'),
obj = new Obj();
obj.A();
I receive the error:
TypeError: Object [object Object] has no method 'A'
however when I run Object.getPrototypeOf(obj) I get:
{ A: [Function], B: [Function] }
I have no idea what I'm doing wrong here, any help would be appreciated.
I cannot reproduce your problem. Here is my setup:
parent.js
var Parent = function() {};
Parent.prototype = {
C: function() {
console.log('Parent#C');
}
};
module.exports = Parent;
child.js
var Parent = require('./parent'),
util = require('util');
var Child = function() {
this.child = 'child';
};
util.inherits(Child, Parent);
Child.prototype.A = function() {
console.log('Child#A');
};
module.exports = Child;
main.js
var Child = require('./child');
child = new Child();
child.A();
child.C();
And running main.js:
$ node main.js
Child#A
Parent#C
The source code is clonable via Git at the following Gist: https://gist.github.com/4704412
Aside: to clarify the exports vs module.exports discussion:
If you want to attach new properties to the exports object, you can use exports. If you want to completely reassign exports to a new value, you muse use module.exports. For example:
// correct
exports.myFunc = function() { ... };
// also correct
module.exports.myFunc = function() { ... };
// not correct
exports = function() { ... };
// correct
module.exports = function() { ... };
I am trying to expose a module. I wanted to expose only one instance of it to all callers, and I want to wait until the module is called to instantiate it. I tried to do this:
var obj = {};
var foobar = function(){
var id=22;
function GetId(){ return ++id; }
return{ GetId: GetId };
};
obj.foobar = (function(){
if (obj.foobar instanceof foobar) {
return obj.foobar;
}
return new foobar();
})();
console.log(obj.foobar.GetId());//23
console.log(obj.foobar.GetId());//24
But really it is just an obfuscation of
obj.foobar = new foobar();
What I had intended was to instantiate obj.foobar = new foobar() when obj.foobar.GetId() is called the first time, and the second time obj.foobar.GetId() is called use the already instantiated version. Although not present here, there are dependencies which require waiting to instantiate new foobar(); so it cannot be executed right away.
How can I accomplish this, what did I miss?
You can use a function call each time you access foobar:
obj.foobar = (function() {
var inst;
return function() {
return inst || (inst = foobar());
};
})();
console.log(obj.foobar().GetId()); // 23
You can also use ECMAScript 5's named accessor properties if the targeted execution environments support them:
Object.defineProperty(obj, "foobar", {
get: (function() {
var inst;
return function() {
return inst || (inst = foobar());
};
})()
});
console.log(obj.foobar.GetId()); // 23
Alternatively, provided that you know the list of methods which can be called on foobar, you can use a more complex solution:
obj.foobar = (function() {
var inst, res = {}, methods = ["GetId"];
function createLazyMethod(method) {
return function() {
if (!inst) {
obj.foobar = inst = foobar();
}
return inst[method].apply(inst, methods.slice.call(arguments, 0));
};
}
for (var i = 0; i < methods.length; ++i) {
res[methods[i]] = createLazyMethod(methods[i]);
}
return res;
})();
console.log(obj.foobar.GetId()); // 23
With this solution, once foobar has been instantiated, calls to its methods come at zero cost.
What I had intended was to instantiate obj.foobar = new foobar() when obj.foobar.GetId() is called the first time
No, that doesn't work. If you call the getId method, there must already be an existing object. Either you define a getter function for the foobar property of the obj which creates the instance on accessing, or you just instantiate it before (as you did in your IEFE and could have shorter done with the assignment, as you said).
Usually, you would use a function (which could also be a constructor) that you call each time and that returns the singleton if it was already created, else it creates one and stores it:
var obj = {
foobar: (function iefe() {
var id, instance;
return function constructor() {
if (!instance) { // create it
id = 22;
instance = {
getId: function getID(){
return ++id;
}
};
}
return instance;
};
})();
};
obj.foobar().getId() // 23
obj.foobar().getId() // 24
I want to access variables by using
MyNamespace.variable1
that are globally accessible. I believe Drupal does something similar, no?
var MyNamespace = {};
MyNamespace.variable1 = value1;
It's just an object really.
What Drupal does is using the following code:
var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
Drupal.attachBehaviors = function (context, settings) {
context = context || document;
settings = settings || Drupal.settings;
// Execute all of them.
$.each(Drupal.behaviors, function () {
if ($.isFunction(this.attach)) {
this.attach(context, settings);
}
});
};
Drupal.detachBehaviors = function (context, settings, trigger) {
context = context || document;
settings = settings || Drupal.settings;
trigger = trigger || 'unload';
// Execute all of them.
$.each(Drupal.behaviors, function () {
if ($.isFunction(this.detach)) {
this.detach(context, settings, trigger);
}
});
};
// …
Using similar code, you can emulate namespaces using JavaScript.
Also, if you have many JS files that each add a "namespace" or Object into a top level package you can do stuff like this:
ModuleA.js
// if Modules is null, create a new object, else use the currently defined instance
var Modules = Modules || {};
Modules.A = {};
// sample instance variable
Modules.A.instanceVar;
// sample function
Modules.A.myFunc = function(param1, param2) {
// do something
}
ModuleB.js
// if Modules is null, create a new object, else use the currently defined instance
var Modules = Modules || {};
Modules.B = {};
// sample instance variable
Modules.B.instanceVar;
// sample function
Modules.B.myFunc = function(param1, param2) {
// do something
}
Then you can of course just call them as you need them Modules.A.myFunc() or Modules.B.myFunc() or Modules.B.instnaceVar = 20;. So you can encapsulate functions as well as variables.
For my code I like to have a root Object, (i.e ) and then added "classes" (objects) to it so that everything has a nice "package like", "OOP" structure to it.
Just create an object. E.g.:
var MyNamespace = {};
MyNamespace.variable1 = ...
Let's say I have a namespace like that:
var myNamespace = {
foo: function() {
},
bar: function() {
}
};
What is the best way to split this code into files defining foo and bar separately?
I'm not worried about loading time - I'll concatenate it back into one file before deployment.
At the start of each file:
if(myNameSpace === undefined) {
var myNameSpace = {};
}
File 1:
myNamespace.foo = function()...
File 2:
myNamespace.bar = function()...
// File1:
// top level namespace here:
var myNamespace = myNamespace || {};
// File2:
myNamespace.foo = function() {
// some code here...
}
In each file follow this pattern:
(function(nameSpace) {
nameSpace.foo = function() { ... };
})(window.nameSpace = window.nameSpace || {});
This way load ordering is unimportant.
Simple define in seperate files like this:
File 1:
var myNamspace = {};
File 2:
myNamespace.foo = function()...
File 3:
myNamespace.boo = function()...
Just make sure you load the files in the right order.
(function (NS) {
NS.Uber = function Uber() {
this.super = new NS.Super(); // yes, it works!
}; //
}(NS = NS || {}));
// ------------- other file -----------------
(function (NS) {
NS.Super = function Super() {
this.uber = new NS.Uber(); // yes, it will also work!
}; //
}(NS = NS || {}));
// -------------- application code ------------
var uber = new NS.Uber();
console.log(uber.super);
var super = new NS.Super();
console.log(super.uber);