I have read couple of posts on SO before posting this question. One thing that's not clear to me is why I'm not able to use multiply function when importing this as module. Isn't module.exports and exports refer to the same object?
Shouldn't multiply be added to the object that is referenced by module.exports. Since exports is an alias for module.exports, I was expecting I'm adding multiply to the same object as I'm not reassigning exports to refer to something else.
module.exports = {
sum : function(a,b){
return a+b;
}
};
exports.multiply = function(a,b){
return a*b;
};
Note that at the start of each nodejs module file, both exports and module.exports point at the same empty object. And you can assign properties to them like below:
exports.item1 = "hi1"
module.exports.item2 = "hi2"
Now both of the exports and module.exports have the same value:
{item1:"hi1", item2: "hi2"}
But when you assign objects to them, only the object that you have given to module.exports matters! In your case if you want to assign an object to module.exports and then add other functions to it, you should first assign the same object to both of them! Now they will point to the same object and if you assign another function to your exports object, it will be accessible via module.exports object, too.
Change the first line of your code and it will work fine!
exports = module.exports = {
sum : function(a,b){
return a+b;
}
};
exports.multiply = function(a,b){
return a*b;
};
You cannot access the multiply function because javascript objects are passed by reference. When you use the line module.exports = {blah}, you create a new object {blah} and set module.exports to point at it. However, exports still points to the old object.
Initially, module.exports and exports point to the same empty object.
So, exports = {} , module.exports = {}. But when you create a new object and have module.exports point at it, Eg:
module.exports = {
sum : function(a,b){
return a+b;
}
};
module.exports will point at the new object, but exports will still point at the old object:
// exports will still point to the old object
console.log(exports) // prints {}
console.log(module.exports) // prints { sum: function() }
Then:
console.log(exports) // prints {}
exports.multiply = function(a,b){
return a*b;
};
console.log(exports) // prints { multiply: function() }
When you import the module, you are returned the value in module.exports, so you won't have access to the multiply function, since that was defined in exports, which references a different object.
If you don't want to worry about this issue, you can just do:
exports = module.exports = {
sum : function(a,b){
return a+b;
}
};
This will make them reference the same object. Hence,
exports.multiply = function(a,b){
return a*b;
};
will work as normal.
Related
I am practicing some module export exercises using a function with a return statement passed inside a module export then to be imported in a new file, it tells me total is not defined? why is this happening?
Code:
file 1:
// Using Async & Await with MODULE EXPORT.
const googleDat = require('../store/google-sheets-api.js');
//passing a let var from a function to another file
let total = googleDat.addVat(100);
console.log(total);
File 2:
function addVat(price) {
let total = price*1.2
return total
};
module.exports = {
total
};
result:
That's because you export a variable that havn't ben initialized AND you didn't exported your function :
function addVat(price) {
//defining variable with let work only in this scope
let total = price*1.2
return total
};
//In this scope, total doesn't exists, but addVat does.
module.exports = {
total //So this is undefined and will throw an error.
};
What you want to do is to export your function, not the result inside.
function addVat(price) {
return price * 1.2;
};
module.exports = {
addVat
};
On file 2, you should be exporting the addVat() function itself and not just its return. Try this one:
exports.addVat = (price) => {
let total = price*1.2
return total
};
I have a JavaScript module that looks something like this:
const Tools = {};
Tools.log = (function {
var logPath = '';
// ... and all the stuff that is returned below
return {
setLogPath: setLogPath,
trace: trace,
debug: debug,
info: info,
warn: warn,
error: error
};
})();
module.exports = Tools;
I require this module in two files using:
var log = require(path/to/module).log;
I would have expected each require statement to create a separate closure, but I find that if I call the setLogPath method in one file, then the log path in the other file changes as well.
This is actually good for me. But I don't understand why only a single closure is being created.
I was expecting the the Tools.log function to be run every time the require statement was used, creating separate closures of the Tools.log function within the files where the require statement is used. This is obviously not the case. In these files, the const Tools = require(path/to/Tools/).log is in the global namespace if that makes a difference.
How does the require statement work?
This code shows what I was expecting:
const A = function() {
var closureVal = 'a'
function changeVal(val) {
closureVal = val;
};
function printVal() {
console.log(closureVal);
};
return {
changeVal: changeVal,
printVal: printVal
};
};
var x = A();
x.printVal(); // a
x.changeVal('x');
x.printVal(); // x
var y = A();
y.printVal(); // a
y.changeVal('y')
y.printVal(); // y
x.printVal(); // x
Actually if I change that test code above to use an IIFE like this:
const A = (function() {
var closureVal = 'a'
function changeVal(val) {
closureVal = val;
};
function printVal() {
console.log(closureVal);
};
return {
changeVal: changeVal,
printVal: printVal
};
})();
var x = A;
x.printVal(); // a
x.changeVal('x');
x.printVal(); // x
var y = A;
y.printVal(); // x
y.changeVal('y')
y.printVal(); // y
x.printVal(); // y
Then I see the same thing as with the require statement. I would expect this because in this test the A function is only being run once, with vars x,y then assigned to the resultant object as pointers.
But I still don't see the why the same is happening with the require statement, where I would expect the function to be run every time the module is loaded
I'm having some issues using sinon stubs and it may stem from how I'm implementing namespacing on the module that I'm looking to stub. Methods directly defined on the prototype are stubbed as I would expect.
...my module.js
const Constructor = require('./constructor') //...just exports a singleton
/* Need to namespace some of my functions and retain the `this` context */
Object.defineProperty(Constructor.prototype, 'es', {
get: function() {
return {
method: require('./implementations/doesSomething.js').bind(this)
}
}
});
module.exports = Constructor;
/* ...testFile.js */
const Constructor = require('./constructor');
const instance = new Constructor();
const sinon = require('sinon');
sinon.stub(instance.es, 'method', function() {
return 'hijacked original method'
});
As mentioned on the Sinon issue tracker, the problem here is that using a plain Object.defineProperty(obj, 'prop') call does something else than plainly creating it using assignment (obj['prop'] = ...).
Generally, if you try defining your property without Object.defineProperty it will be stubbable, but using defineProperty (without creating a special configuration) will make it impossible to stub the property. The reason is simply that the default values for writeable and configurable are false! You cannot delete them or change them. And if you can't do that, then Sinon won't help you. So, generally, you need to add writeable: true, configurable: true in your property definition.
Now there was one more thing I forgot to answer originally:
You are not trying to wrap a function on Constructor.prototype.es.method - what you are trying to wrap is the function on the object returned by the getter on the property for es. That will never work. Why? Simply because the returned object is never the same. You are creating a new object around method each time. If you really need to replace/stub the method property, you actually need to replace the entire Constructor.prototype.es property instead. If you need this namespacing, you can vastly simplify this, and also enable stubbing, like this:
Constructor.prototype.es = {};
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
}
An expanded, fully working example (Gist for download):
// constructor.js
const someFunction = function(){
return this.value;
}
function Constructor(){ };
Constructor.prototype.es = { value : 100 };
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
});
// test.js
const instance = new Constructor();
console.log(instance.es.method()) // => 100
// using this won't work:
// sinon.stub(instance.__proto__.es, 'method').returns(42);
// because the getter is returning a _new_ function each time
// therefore you need to attack the actual getter function:
const stub = sinon.stub(instance.__proto__.es, 'method').value(()=>42);
console.log(instance.es.method()) // => 42
stub.get(()=>()=>84);
console.log(instance.es.method()) // => 84
stub.restore();
console.log(instance.es.method()) // => 100
// the above is working on the prototype, can't we do this on the instance?
// yes, we can, but remember that the `es` object is shared, so we
// can avoid modifying it by shadowing it further down the prototype
instance.es = { method: sinon.stub().returns(256) };
console.log(instance.es.method()) // => 256
delete instance.es
console.log(instance.es.method()) // => 100
<script src="https://unpkg.com/sinon#2.3.5/pkg/sinon.js"></script>
Coming across something unexpected. I have the following code:
var actions = require("../actions.js"); // an object of objects
module.exports = {
rando_function: function(){
console.log(actions); // empty object
}
}
I expected to log an object of objects, but it's empty. Whereas, this works:
module.exports = {
rando_function: function(){
var actions = require("../actions.js"); // an object of objects
console.log(actions); // an object of objects
}
}
What am I doing wrong here?
sir/madam exlain the flow of node.js from client to server with the dynamic parameters passing from userinterface to api's based up on these parameters we will get the output from api.for example sabre api etc..
exports.flightDestinations = function(req, res) {
var callback = function(error, data) {
if (error) {
// Your error handling here
console.log(error);
} else {
// Your success handling here
// console.log(JSON.parse(data));
res.send(JSON.parse(data));
}
};
sabre_dev_studio_flight.airports_top_destinations_lookup({
topdestinations: '50'
}, callback);
};
we want this value 50 from user...and how to give this value?and how to call this function in node.js.
The exports variable is initially set to that same object (i.e. it's a shorthand "alias"), so in the module code you would usually write something like this:
var myFunc1 = function() { ... };
var myFunc2 = function() { ... };
exports.myFunc1 = myFunc1;
exports.myFunc2 = myFunc2;
to export (or "expose") the internally scoped functions myFunc1 and myFunc2.
And in the calling code you would use:
var m = require('mymodule');
m.myFunc1();
where the last line shows how the result of require is (usually) just a plain object whose properties may be accessed.
NB: if you overwrite exports then it will no longer refer to module.exports. So if you wish to assign a new object (or a function reference) to exports then you should also assign that new object to module.exports
It's worth noting that the name added to the exports object does not have to be the same as the module's internally scoped name for the value that you're adding, so you could have:
var myVeryLongInternalName = function() { ... };
exports.shortName = myVeryLongInternalName;
// add other objects, functions, as required
followed by:
var m = require('mymodule');
m.shortName(); // invokes module.myVeryLongInternalName