What's the difference between these two module.exports? - javascript

So the first one being something like:
myFile.js
var name = "Peter";
module.exports.sayHello = function () {
console.log('Hello ' + name);
}
And the second one
myFile.js
module.exports = function () {
var name = 'Mary';
function sayHello () {
console.log('Hello ' + name);
}
return {
sayHello : sayHello
};
}();
Essentially it's the same thing right? If not, what's the difference and what's the pros and cons of each method?

Why do we need modules?
When you have a code like this:
// module 1
var a = 1;
var x = function (){
return a;
};
// module 2
var a = 2; // duplicated variable declaration
var y = function (){
return a;
};
// main
console.log(x()); // BUG: this should read value from module 1 instead of module 2
console.log(y());
It will lead to error, since the a variable was already taken by the first module. You need to define modules somehow.
Using a prefix
By old-style procedural programming you would add a prefix to separate modules:
// module 1
var m1_a = 1;
var m1_x = function (){
return m1_a;
};
// module 2
var m2_a = 2;
var m2_y = function (){
return m2_a;
};
// main
console.log(m1_x());
console.log(m2_y());
But this makes the code less readable.
Using closures
By javascript you have closures, which make things a little bit easier:
// module 1
var x = (function (){
var a = 1;
var x = function (){
return a;
};
return x;
})();
// module 2
var y = (function (){
var a = 2;
var y = function (){
return a;
};
return y;
})();
// main
console.log(x());
console.log(y());
But still you have different modules in a single file, so that file will be really big and hard to maintain.
Using the node.js module loader
By node.js you can move the code of different modules to separate files, so it will be easy to maintain the code of different modules, since you will be able to find the relevant part of the code much faster:
m1.js
var a = 1;
var x = function (){
return a;
};
module.exports = x;
m2.js
var a = 2;
var y = function (){
return a;
};
module.exports = y;
main.js
var x = require("m1");
var y = require("m2");
console.log(x());
console.log(y());
You can do the same in the browser
The simplest node.js style browser module loader I could come up with so far, is this:
var cache = {};
function require(name){
if (name in cache)
return cache[name];
var uri = "./" + name + ".js";
var xhr = new XMLHttpRequest();
xhr.open("GET", uri, false);
xhr.send(null);
var moduleCode = xhr.responseText;
var fn = new Function("module", moduleCode);
var module = {};
fn(module);
cache[name] = module.exports;
return cache[name];
};
Ofc. it is much safer to use browserify, webpack, require.js and other more sophisticated libs, I just wanted to show you, it is not that hard to write a loader.
What did we learn from all of this?
Both node.js modules and closures are for modularization. You should not mix them, since they solve the same problem, and mixing them will lead only to confusion!

For me it's the same thing.
Maybe the first example is more common.
You can use both, according to the rest of your code.

Yes they are basically the same. You just don't need the verbosity of the second example.
In the first example you are adding a named property to the already existing module.exports object injected by node.js, in the second example you are overriding the original object - there is no difference for the consuming end.

Lets go to the basics of module mechanism in NodeJS. For every JS
file the ground reality is which happens on the top of file:
var exports = module.exports = {};
Whenever we try to fetch the import it retrieves module.exports only
If we do both in Js file
exports.key = "key1" and module.exports = {key : "VAL"}
only the module.exports is fetched during the import according to the rule.
Now coming back to your question Adding module.exports.sayHello will
add the reference to the {} which is common with exports variable too.
However if you do
module.exports = function () {} // some function
it breaks the chain and it is only assigned to module.exports and not
exports variable.
This is why if we add any key to exports variable is retrieved via
module.exports during import! Hope it clarifies!
A very good article on this https://www.sitepoint.com/understanding-module-exports-exports-node-js/

Related

Nodejs Cyclic Dependency with Revealing Module Pattern

I've been running into this issue lately and am looking for a good solution.
Below is the basic setup.
In c.js, a is an empty object. Currently I got around this by putting the var a=require('./a.js') inside the function (cFunction) that needs access to module a's methods. But is that the best way to go about this?
Thanks,
David
main.js
var a = require('./a.js');
a.js
module.exports = (function() {
var b = require('./b.js');
function aFunction() {
console.log("aFunction");
}
return {
aFunction: aFunction
};
})();
b.js
module.exports = (function(){
var c = require('./c.js');
function bFunction(){
console.log('bFunction');
}
return {
bFunction: bFunction
};
})();
c.js
module.exports = (function(){
var a = require('./a.js');
console.log(a); //empty object
function cFunction(){
a.aFunction(); //undefined
console.log('cFunction');
}
return {
cFunction: cFunction
};
})();

Nodejs:Object variable in node.js [duplicate]

This question already has answers here:
Understanding Node.js modules: multiple requires return the same object?
(7 answers)
Closed 7 years ago.
I have two files. I am creating the multiple object of one file into other.
module1.js
var a = 5;
var check1 = function(){
a = a + 10;
console.log(a);
}
exports.check = check1;
module2.js
var c = require('../module1');
var d = require('../module1');
c.check();
d.check();
The output is 15 & 25.
When you declare a variable using var, the scope is local. And i am creating two instances of module.js. So why is it getting declared at global level because the output is 15 & 25?
I need output as 15 & 15 as i want to use this variable as object level variable. What should i do?
Whenever you do a require, it returns a reference to the module that has already loaded into memory if there is any. Otherwise, it'll load the module first, then return the reference to it. More info in docs.
So, both your variables are actually pointing to the same object. You can verify this by requireing any modules.
var a = require('http');
var b = require('http');
console.log(a==b); // true
That is to prevent infinite loops while loading cyclic dependencies.
Depending on your module's code, you can do several things to solve the issue.
You can move the variable definition inside your function for example:
var check1 = function(){
var a = 5;
a = a + 10;
console.log(a);
}
exports.check = check1;
Or you can write a function that creates a new object each time you call it.
var create = function () {
var a = 5;
var check1 = function(){
a = a + 10;
console.log(a);
}
return {
check1: check1
}
}
exports.create = create;
And in your main file:
// or you can store require('./module1') to a single variable
var a = require('./module1').create();
var b = require('./module1').create();
a.check1();
b.check1();
NodeJS module system uses caching to return same instance for all references to the same module (Reference).
This results in your code having the same object instance in c & d.
If you want to have 2 separate instances, try like this:
module1.js
function Check() {
var a = 5;
return {
check: function() {
a = a + 10;
console.log(a);
}
};
}
exports.Check = Check;
module2.js
var Check = require('../module1').Check;
var c = Check();
var d = Check();
c.check();
d.check();

Issue regarding Javascript Modular pattern

I was reading javascript Modular pattern from this url http://viralpatel.net/blogs/javascript-module-pattern/ and
http://www.codeproject.com/Articles/247241/Javascript-Module-Pattern
and some time confusion arise in my mind. so here i am putting things where i get some confusion. please help me to understand all.
Question 1
see the below code. all private variable and function declared in module with var keyword. here pub object also declared with var keyword.
it means pub is private. so when pub is private then how people can call pub related function from out side like below code
calling syntax
CalcModule.add(2,10);
CalcModule.add(5,15);
CalcModule = (function(){
var pub = {};
var mem = new Array(); //private variable
var storeInMemory = function(val) { //private function
mem.push(val);
};
pub.add = function(a, b) {
var result = a + b;
storeInMemory(result); //call to private function
return result;
};
pub.sub = function(a, b) {
var result = a - b;
storeInMemory(result); //call to private function
return result;
};
pub.retrieveFromMemory = function() {
return mem.pop();
};
return pub;
})();
CalcModule.add(2,10);
CalcModule.add(5,15);
console.log(CalcModule.retrieveFromMemory()); //outputs 20
console.log(CalcModule.retrieveFromMemory()); //outputs 12
Question 2
Separating Module across different JS files: Augmentation
file1.js
var CalcModule = (function($, pub){
//jQuery will still be available via $
var mem = new Array(); //private variable
pub.storeInMemory = function(val){
mem.push(val);
};
pub.retrieveFromMemory = function(){
return mem.pop();
};
return pub;
})(jQuery, CalcModule || {});
file2.js
var CalcModule = (function($, pub){
//jQuery will still be available via $
pub.add = function(a,b){
var result = a + b;
pub.storeInMemory(result);
return result;
};
pub.sub = function(a,b){
var result = a - b;
pub.storeInMemory(result);
return result;
};
return pub;
}(jQuery, CalcModule || {}));
see this function($, pub) syntax. why dollar sign is there and why pub need to pass there.
Question 3
what is the difference between module Augmentation and sub module ?
Question 4
Extending existing module module
var Module1 = ( function (oldModule) {
var
//assigning oldmodule in to a local variable.
parent = oldModule;
//overriding the existing privileged method.
parent.privilegedMethod = function ( ){
//do something different by overriding the old method.
};
//private method accessing privileged method of parent module.
var privateMethod2 = function ( ) {
parent.privilegedMethod();//can access privileged method of Module
parent.publicMethod1(); //can access public method of Module
}
return {
newMethod : function ( ) {
///do something for this brand new module.
///use some functionality of parent module.
/// parent.privilegedMethod( );
}
};
} )(Module);//
Module object is the existing module that I want to extend.
how anyone can understand the above code extend the module. just by this syntax (Module) ?
Question 5
if we write module in 5 separate js file then which file we need load first. what will be the order of loading those module related s file ?
Answer 1
Because at the end it's returning pub so you'll have access to all its methods
CalcModule = (function(){ return pub; }());
CalcModules === pub
Answer 2
function($, pub)
This is the declaration of the anonymous function that is called at the end of the code
Here we have the effective call passing jQuery and your module
(jQuery, CalcModule || {}));
N.B.
We are passing jQuery as first parameter and CalcModule as second only if exist otherwise an empty object (CalcModule OR {}).
The first time the function is called CalcModule doesn't exist and so you'll end up passing an empty object, the second time CalcModule exist because has been created by the previous call.
This is done to make it order agnostic.
So we can deduce
First Call
$ === jQuery
pub === {}
Second and next Calls
$ === jQuery
pub === CalcModule
You have to pass CalcModule to the function so it can be expanded.
This
(function($, pub){...}(jQuery, CalcModule || {}));
is exactly equal to this
var anonFunc = function($, pub){...};
anonfunc(jQuery, CalcModule || {});
Answer 3
Augmentation: you are adding functionality to the same module
pub.add = function(a,b){}
pub.sub = function(a,b){}
Sub-Module: you are adding a module to another module
subModule.add = function(a,b){}
subModule.sub = function(a,b){}
pub.subModule = function(a,b){ return mySubModule; }
Answer 4
You are passing Module but it's creating a brand new module that can USE the Module you have passed, this is more like a sort of Inheritance than Augmentation
Answer 5
Depends, but generally it's indifferent because you're just declaring the functionalities of your Module.
The only case where you need to respect an order is when a functionality construction depends on another functionality of the module.

Node.js pass variable to module vs pass variable to every module function

I'm learning node.js and interested in is there any difference between following two cases.
I.E. I have some variable myvar (like db connection or just constant string "test") that needed to be passed in many modules and submodules.
First case.
Create modules, that accept that variable as a param:
submodule.js:
var option
, submodule = {};
submodule.func = function(){
...
var something = option;
...
}
module.exports = function(opts){
option = opts;
return submodule;
}
module1.js:
var option
, submodule
, module1 = {};
module1.func = function(){
...
submodule.func();
...
var something = option;
...
}
module.exports = function(opts){
option = opts;
submodule = require('./submodule')(opts);
return module1;
}
In this case if submodule is used in several modules with same myvar value (i.e. 2 modules) submodule's module.exports function will be called 2 times. In node.js mans it said that "Modules are cached after the first time they are loaded". And I can't understand is this module cached or not.
Another case:
That myvar can be passed as parameter to module functions. So code will look like:
submodule.js:
function func(option){
...
var something = option;
...
};
exports.func = func;
module1.js:
var submodule = require('./submodule');
function func(option){
...
submodule.func(option);
...
var something = option;
...
};
exports.func = func;
So the question is:
Is there any difference between this two cases or they are same?
I'm not exactly sure what you're asking here, but if you need to pass values into your modules you should make sure to export functions that accept parameters. When they say that a module is cached, it means that your module is only initialized once. Think of your module as an object:
var a = 1;
var b = 2;
console.log("init!");
module.exports.test = function(){
console.log("this is a function!");
}
Here, a, b, and the first log will run only once. This is when the module is requested and is then cached. When you do a
var example = require("module")
If it was never created it'll initialize a, b, and do the log message. If it was already created it will just give you a reference to what you exported. Each time you call:
example.test()
It will output: this is a function!
But you will NOT get the a, b, and the first log run again.
Think of all statements not exported as private static variables of that object.
Here is another fully working example:
app.js
var s = require("./sample");
var y = require("./sample");
s.test();
y.test();
s.test();
console.log("finished");
sample.js
var a = 1;
var b = 2;
console.log("init!");
function test() {
console.log("here! " + a);
a++;
}
exports.test = test;
This all outputs:
init!
here! 1
here! 2
here! 3
finished
Does this help at all?

CommonJS Modules (with nodejs), strangeness

Okay, experimenting with CommonJS module system in the context of NodeJS.
module.exports = pricingCalculator;
function pricingCalculator (options) {
var target = {};
return target;
}
This works. Presumably the variable declaration of pricingCalculator is hoisted to the top of the function scope, so the misordering doesnt quite matter as the function is passed by reference anyway. I get that. What I dont understand is why the following two versions that work:
module.exports = pricingCalculator;
var pricingCalculator = function (options) {
var target = {};
return target;
}
Fail.
module.exports = pricingCalculator;
pricingCalculator = function (options) {
var target = {};
return target;
}
Fail. Curious to understand deeply what is going on.
In first example function is defined before assignment (java script way).
In second and third examples assignments are executed in sequence.
http://studiokoi.com/blog/article/execution_order_of_functions_and_variables_in_javascript_and_actionscript

Categories