Difference between multiple ways of referencing exported attribute - javascript

I'm using socket.io and need to export the io object for use in other files. Controller A works and successfully emits the message. What's weird is that Controller B and C do not reference the .io correctly. Is there any difference between the three ways of referencing .io?
// index.js
exports.register = function (server, options, next) {
var onlineUsers = {};
var io = require('socket.io')(server.select('collaboration').listener);
io.on('connection', function (socket) {
socket.on('is_online', Handlers.is_online.bind(null, socket));
socket.on('disconnect', Handlers.is_offline.bind(null, socket));
});
exports.io = io;
next();
};
// controllerA.js
var io = require('./collaboration/index');
function testFunc() {
io.io.emit('testing', {data: 'some data'});
}
// controllerB.js
var io = require('./collaboration/index').io;
function testFunc() {
io.emit('testing', {data: 'some data'});
}
// controllerC.js
var index = require('./collaboration/index');
var io = index.io;
function testFunc() {
io.emit('testing', {data: 'some data'});
}

This has to do with timing: exports.io is created only when the register() is called. Before that, exports.io is undefined.
This is also reflected in your controllers:
controllerA stores a reference to the exports object of index.js. At the time you require index.js, exports.io doesn't yet exist but that's not a problem because you reference it later, in testFunc (which does mean that register() has to be called before testFunc, otherwise io.io is still undefined);
controllerB and controllerC reference exports.io directly, at the time the require is called. At that time though, it doesn't exist yet. In other words, they are storing an undefined reference, and their testFunc's fail because of that;
Here's a simplification of what's happening:
// controllerA
var obj = {};
var io = obj;
obj.io = 'hello';
console.log(io.io);
// controllerB
var obj = {};
var io = obj.io;
obj.io = 'hello';
console.log(io);
// controllerC
var obj = {};
var index = obj;
var io = index.io;
obj.io = 'hello';
console.log(io);
This logs:
hello
undefined
undefined

Related

How to export a variable from a module in JavaScript?

According to this post we know that variables can be exported from one module in JavaScript:
// module.js
(function(handler) {
var MSG = {};
handler.init = init;
handler.MSG = MSG;
function init() {
// do initialization on MSG here
MSG = ...
}
})(module.exports);
// app.js
require('controller');
require('module').init();
// controller.js
net = require('module');
console.log(net.MSG); // output: empty object {}
Those above codes are in Node.js and I get one empty object in my controller.js. Could you please help me figure out the reason of this?
Update1
I have updated the above codes:
// module.js
(function(handler) {
// MSG is local global variable, it can be used other functions
var MSG = {};
handler.init = init;
handler.MSG = MSG;
function init(config) {
// do initialization on MSG through config here
MSG = new NEWOBJ(config);
console.log('init is invoking...');
}
})(module.exports);
// app.js
require('./module').init();
require('./controller');
// controller.js
net = require('./module');
net.init();
console.log(net.MSG); // output: still empty object {}
Output: still empty object. Why?
When you console.log(net.MSG) in controller.js, you have not yet called init(). That only comes later in app.js.
If you init() in controller.js it should work.
Another issue i discovered through testing.
When you do MSG = {t: 12}; in init(), you overwrite MSG with a new object, but that doesn't affect handler.MSG's reference. You need to either set handler.MSG directly, or modify MSG: MSG.t = 12;.

NodeJS - How to assign constructor to module.exports in self-executing function?

I'm trying to assign a constructor in a self-executing function in NodeJS. I'm pretty sure it's not working because my parameter is a variable pointing to module.exports, but I'm curious if there's a way to make it work while staying as close to the self-executing format as possible.
Here's how the code is being called...
var TemplateEngine = require('./templateEngine');
templateEngine = new TemplateEngine({engine: 'swig'}); // "object is not a function"
Here's an example of code that works fine...
var assert = require('assert');
var swig = require('swig');
// Constructor
var TemplateEngine = function(args) {
assert.ok(args.engine, 'engine is required');
var templateEngine = {};
templateEngine.engine = args.engine;
templateEngine.Render = function(templateString, model) {
var result = swig.render(templateString, model);
return result;
};
return templateEngine;
};
module.exports = TemplateEngine;
and here's an example of the code style I'd like to use, but which produces a "TypeError: Object is not a function" error because I'm not actually assigning to module.exports, just a variable that copied whatever it was pointing to.
(function(templateEngine) {
var assert = require('assert');
var swig = require('swig');
templateEngine = function(args) {
assert.ok(args.engine, 'engine is required');
var templateEngine = {};
templateEngine.engine = args.engine;
templateEngine.Render = function (templateString, model) {
var result = swig.render(templateString, model);
return result;
};
return templateEngine;
};
})(module.exports);
Is there a way for me to use the above self-executing format and have my module export a Constructor?
In your second example, you are simply overwriting the templateEngine parameter, and that's not going to have any effect.
To get the same result as your first example, simply:
Pass module into your IIFE:
(function(module) {
})(module);
Assign a property to that:
(function(module) {
var assert = require('assert');
var swig = require('swig');
module.exports = function (args) {
...
};
})(module);

node.js instantiate class multiple times

I have a class file that creates socket connections based on the parameter passed in during instantiate.
When I try to instantiate this file multiple times (for loop) it looks like the node.js is handling it like singleton.
Is there a way I can create new instances from a same js file that can hold its own arguments passed?
app.js
for(var i....){
require('./controller/sockets')(param[i]);
}
./controller/sockets
var util = require('util');
var param
Socket = function(iParam) {
param = iParam;
};
util.inherits(Socket,EventEmitter);
Socket.prototype.test = function(){
return param;
};
module.exports = Socket;
Thank you!
Your constructor doesn't actually create anything. All it does it store an argument in a variable. So, when you call it N times, that's all it does is store a different value into the same variable N times in a row.
Your code is essentially doing this:
var param;
var Socket = function(iParam) {
param = iParam;
}
for(var i....){
Socket(param[i]);
}
It is not clear to me what you want it to do, but perhaps the constructor needs to create an object (probably using new), initialize it and then return it.
If you want a new Socket object back from each call to the constructor, then you can do it like this:
var util = require('util');
function Socket(iParam) {
this.param = iParam;
}
util.inherits(Socket,EventEmitter);
Socket.prototype.test = function(){
return this.param;
};
module.exports = function(x) {
return new Socket(x);
};

Calling public method within module javascript

I'm trying to call a public method from within the module pattern.
I'm using the module pattern because it allows for splitting into various different JS files, to make the code more organised.
However when I call the public method, I get a TypeError and also typeof remains undefined.
Please help!! Thanks in advance.
main.js
function MainObject() {
this.notify = function(msg) { console.log(msg); }
}
var connObj = require("./myextobj");
var mainObj = new MainObject();
connObj.connection.handle = mainObj;
console.log(typeof connObj.connection.connect); // undefined
connObj.connection.connect(); // TypeError: Object has no method 'connect'
myextobj.js
module.exports = {
connection: function () {
this.handle = eventhandle;
this.connect = function() {
// connect to server
handle.notify("completed connection....");
}
}
}
It's because you're exporting an object containing connection: function (), which is a constructor function and needs newing-up. Then you can access the this properties attached to that particular instance:
var connection = require("./myextobj").connection; // reference the constructor function
var conn = new connection(); // new-up connection
console.log(typeof conn.connect); // -> function
Edit:
If the only thing exported by myextobj.js is the constructor function, there's no need to wrap it up in a literal object. I.e. you could do:
module.exports = function Connection() {
this.handle = eventhandle;
this.connect = function() {
handle.notify("completed connection....");
}
}
then use like so:
var Connection = require("./myextobj");
Note: .connection is no longer appended to the end to reference the function.
Give this a shot.
var module = {};
module.exports = {
connection: function () {
return {
handle: eventhandle,
connect: function () {
// connect to server
handle.notify("completed connection....");
}
}
}()
}
module.exports.connection.connect()

Call function of app.js from within module in node.js?

Let's say I have the following app.js (obviously very simplified):
var express = require('express'),
app = express.createServer();
// include routes
require('./lib/routes')(app);
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
And then I have the routes module:
module.exports = function(app){
app.get('/some/route', function(req, res){
var fooBar = foo(),
fooBar2 = foo2();
res.end(fooBar + fooBar2);
});
};
This obviously doesn't work since foo and foo2 weren't defined within the module. Is there a way to make this work, or at least a different pattern to better accomplish what this?
Well you can just put these two functions in an object and pass them on the initialization of the routes.js .
var express = require('express'),
app = express.createServer();
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
var fns = {foo : foo, foo2: foo2}
// include routes
require('./lib/routes')(app, fns);
in routes:
module.exports = function(app, fns){
app.get('/some/route', function(req, res){
var fooBar = fns.foo(),
fooBar2 = fns.foo2();
res.end(fooBar + fooBar2);
});
};
This is how would I do it. You can also include them in the app object. Beside passing them in init functions, you can also export those two functions and require them in routes.js.
var express = require('express'),
app = express.createServer();
// some random function
var foo = function() {
return 'bar';
};
// another random function
var foo2 = function() {
return 'bar2';
};
module.exports = {foo : foo, foo2: foo2}
// include routes
require('./lib/routes')(app, fns);
in routes:
module.exports = function(app){
var fns = require('../app.js');
app.get('/some/route', function(req, res){
var fooBar = fns.foo(),
fooBar2 = fns.foo2();
res.end(fooBar + fooBar2);
});
};
But I don't like the idea of it, since it makes circular dependencies. Don't have any good feelings about them.

Categories

Resources