I would like to achieve module pattern in JS. I followed some posts in google and starting writing my own.
here is what I would like to achive
mns - will be the name space for my lib
math - will be one of the sub-module in mns
and I want all these modules in separate files.
here is mns.js file code (it is just for namespace no functions in it)
var mns = (function () {
return {};
})();
here is math.js code(i want this as a submodule for mns)
var submodule = (function (mns) {
var math = (function(){
var counter = 0;
var incrementCounter = function () {
return counter++;
}
var resetCounter = function () {
alert( "counter value prior to reset: " + counter );
counter = 0;
}
})();
mns.math = math;
return mns;
})(mns || {});
I am expecting application.js will call like below
mns.math.incrementCounter();
mns.math.resetCounter();
Right now, I am getting Cannot read property of undefined error when calling incrementCounter & resetCounter.
Please guide me in this.
All is looking good, except for the math module:
var math = (function(){
var counter = 0;
var incrementCounter = function () {
return counter++;
}
var resetCounter = function () {
alert( "counter value prior to reset: " + counter );
counter = 0;
}
})();
In order to use incrementCounter and resetCounter you have to return them in an object (So that math will be set to something).
Something like this should work:
var math = (function(){
var counter = 0;
var incrementCounter = function () {
return counter++;
}
var resetCounter = function () {
alert( "counter value prior to reset: " + counter );
counter = 0;
}
return {
incrememtCounter: incrememtCounter,
resetCounter: resetCounter
}
})();
Following is the way, I achieved it. Please suggest better approach
mns.js file
var mns = {};
math.js file
mns.math = (function(){
var counter = 0;
var incrementCounter = function () {
return counter++;
};
var resetCounter = function () {
alert( "counter value prior to reset: " + counter );
counter = 0;
};
return{
incrementCounter : incrementCounter,
resetCounter : resetCounter
}
})();
Rather than dealing with the semantics of creating closures, I recommend using Browserify to handle your module patterns for you. This allows you to separate everything into multiple files, as well as use the file name as an identifier for your modules. It helps to reduce the amount of boilerplate and makes the code easier to understand. It also mimics NodeJS modular CommonJS syntax which is nice as well.
I think what you're looking for is this...
// mns.js
(function(window) {
var mns = function() {
// your private code here...
return {
// public module interface...
}
}();
window.mns = mns;
})(window);
// math.js
(function(mns) {
var math = function() {
// your private code here...
return {
// public module interface...
}
}();
mns.math = math;
})(window.mns);
In your HTML page, you will need to load mns file first, and then math file. Or maybe you could use some tool to connect these files and load a unique minified file like mns.min.js. For me Gulp.js is a magnificent tool for that propose. Use some concat operation of the Gulp.js to join the file in an specific order, like I said.
If you want a real-world example, see this:
https://github.com/viniciusknob/queiroz.js/blob/master/dist/queiroz.js
Related
How do we return function using module.exports in nodeJS?
file_1 book.js
module.exports = function() {
var points = 0;
return {
rate: function(value) {
points = value;
},
get: function() {
return points;
}
}
}
book.js is root file. We create two different instances but can not get the methods of root to script.js file.
file_2 main.js
var bA = require('./book.js');
var bB = require('./book.js');
bB.rate(10);
bB.get();
Output => can not find rate and get method.
Because the function returns an object with references to the rate and get functions, you need to execute it with a () on require like so:
var book = require('./book.js')();
book.rate(10);
book.get();
You're returning a function which returns an object.
Call the function and get the object
/*file_2 main.js*/
var bA = require('./book.js')();
var bB = require('./book.js')();
bB.rate(10);
bB.get();
Just in case if someone's facing same problem as me
I had something issue with my code. Lately realised I was making some API call and so return returned an object before fetching the value from API endpoint
I added async in front of function call and it worked!
var util=require('./app/Utils')
const url=await util.getInfo();
You can also provide a name to your anonymous export function as
module.exports.myfun = function() {
var points = 0;
return {
rate: function(value) {
points = value;
},
get: function() {
return points;
}
} }
Then use the function in another file as
var inc = require('./comp.js');
var mod = inc.myfun();
mod.rate(10);
console.log(mod.get());
In this way you don't need to have '()' at the time of required, though that option can also be used
I'm trying to make something in JS and using browserify to use other JS files in my main code. I know I have node and browserify installed correctly because I can enter "browserify example.js -o bundle.js" in the terminal and run his code just fine.
I finally just added my function (soundoff()) to his system.js code below and tried calling it the same way he called the functions in this file in the second code snippet...
module.exports = (function (){
var _final = "",
DEFAULT_STEP = 15,
DEFAULT_TURN = Math.PI / 4;
/* Initializes an L-System using the supplied
* axiom, rules, and number of iterations
* params:
* - axiom: the starting string
* - rules: the array of rules as string -> string
* key/value pairs (i.e. ["key", "value"]
* - iterations: the number of iterations to carry out
*/
function lsystem(axiom, rules, iterations) {
_final = axiom;
for(var i = 0; i < iterations; i++) {
_final = apply(_final, rules);
}
return _final;
}
function soundoff(done) {
return done;
}
You see below here I'm calling it the same way he's calling other functions from the ls reference/function/module but I still get "Uncaught TypeError: ls.soundoff is not a function"
window.onload = function() {
var ls = require('./lsystem.js');
var wonk = ls.soundoff("wonk!");
// Set up the algae demo
var aIter = document.getElementById("algae-iterations"),
aOut = document.getElementById("algae-output");
aOut.value = ls.algae(0);
aIter.onchange = function() {
aOut.value = ls.algae(aIter.value);
}
Without calling this function it works perfectly. Those aren't the whole code files but I know everything else if fine since they work, I just can't figure out why I can't have a function I put in like that and call it...
Thanks in advance for the help! :)
That wont work. Because soundoff is a function within lsystem function, which means soundoff is not accessible as a property.
If you can change your lsystem to export an Object and do this, it will work.
module.exports = {
soundoff : function(done){
return done;
}
}
Edit :
Method 1:
file1.js
module.exports = (function func(){
return {
soundoff : function(done){
return done;
}
}
});
file2.js
var func = require('file1');
var obj = func();
obj.soundoff('wonk');
Method 2.
file1.js
module.exports = {
soundoff : function(done){
return done;
}
}
file2.js
var obj = require('file1');
obj.soundoff('wonk');
Method: 3
There are other dirty ways where you could, use the this property in conjunction with Function.prototype.call, but I would advise you not to go for it. Do not use it, like, ever. Highly volatile.
file1.js
module.exports = (function func(){
this.soundoff = function(done){
return done;
}
});
file2.js
var func = require('file1');
func.call(func);
func.soundoff('wonk');
Is there any difference b/w the following 2 patterns? What is the advantage of self-executing the first one?
var testModule = (function () {
var counter = 0;
return {
incrementCounter: function () {
return counter++;
},
resetCounter: function () {
console.log( "counter value prior to reset: " + counter );
counter = 0;
}
};
})();
testModule.incrementCounter(); // 1
Next:
var testModule2 = function () {
var counter = 0;
return {
incrementCounter: function () {
return counter++;
},
resetCounter: function () {
console.log( "counter value prior to reset: " + counter );
counter = 0;
}
}
}
var result = testModule2();
result.incrementCounter(); //1
The first one is a singleton - you can clone it, of course, but it'll be quite awkward, first, and won't make copies of that private variables: all the methods of all the cloned objects will still work with the same var counter. That's why it's suitable for making service-like things.
The second one is a variant of constructor function actually - and it's suitable for creating multiple things based on a single template. Its drawback (comparing with classical prototype-based templates) is that all the functions defined in it will be created anew each time a testModule2 is invoked. Its advantage - private variables, an independent set for each new object (note the difference with cloning the objects created with the first approach).
I will give you a sample example of my problem to remove the logical complexity and let you be focus on the important part. Of course, this example will be a bit useless...
I have a tree structure where node are like that
{
path: "...",
childs : []
}
Now, I have to write all the full paths from root to each leaf in an array.
My design is very poor:
function listPaths(node) {
var result = [];
function listForNode(n, parentFullPath) {
var thisPath = parentFullPath + "/" + n.path;
result.push(thisPath);
n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
listForNode(node, "");
return result;
}
It could be nice but I can't write the test with Mocha without having an insane 600 line code test file. At this moment, you should be asking why. The reason is the complexity of the real purpose, that's not relevant for my question. My goal is to having something 'mockable' cause I'm used to. (Java dev). But I fail.
Do you have any pattern that I can use to resolve this one? I'm not really good at JS patterns. :/
Visitor? Making an Y Combinator? So many possibility...
Thank you for reading me
You need to remember that functions are first class citizens in javascript.
I see that essentially what you have is something like
function createVisitor(parentsAccumulatorInitialValue, parentsAccumulator){
var visitor = function myVisitor (node) {
var result;
function listForNode(n, parentsAcc) {
var thisPath = parentsAccumulator(parentsAcc, n);
result.push(thisPath);
n.childs && n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
result = [];
listForNode(node, parentsAccumulatorInitialValue());
return result;
}
return visitor;
}
var listPaths = createVisitor(
function parentInit () {
return "";
},
function parentAcc (parentFullPath, n) {
return parentFullPath + "/" + n.path;
});
But that's not the only abstraction you could take care of:
function createVisitor2(
totalAccumulatorInitialValue,
totalAccumulator,
parentsAccumulatorInitialValue,
parentsAccumulator){
var visitor = function myVisitor (node) {
var total;
function listForNode(n, parentsAcc) {
var thisPath = parentsAccumulator(parentsAcc, n);
total = totalAccumulator(total, thisPath, n);
n.childs && n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
total = totalAccumulatorInitialValue();
listForNode(node, parentsAccumulatorInitialValue());
return total;
}
return visitor;
}
var listPaths2 = createVisitor2(
function totalInit() {
return [];
},
function totalAcc(total, thisPath, n){
total.push(thisPath);
return total;
},
function parentInit () {
return "";
},
function parentAcc (parentFullPath, n) {
return parentFullPath + "/" + n.path;
});
Which might be pretty reasonable, but as you can see, I'm already beginning to have trouble finding appropriate names for these variables. In fact, I'd say the name of our function is bad, as doesn't create anything strictly like a visitor object I know of. However, it does work (BTW, I've slightly modified it to handle nulls as well as empty arrays):
> listPaths( { path:"foo",
childs: [{path:"bar", childs: null}, {path:"bob", childs: null}]})
["/foo", "/foo/bar", "/foo/bob"]
It can be modified even further so that your trees don't strictly even have the same structure... but we're already at 4 parameters, which isn't great. It'd be better if your visitor creator were passed a single extensible object with all the necessary methods or values. For instance, maybe (pseudocode):
function createVisitor3(opts) {
//assume we've defined GetDefaults() somewhere local to createVisitor3
// as well as assume that extend is defined somewhere that copies properties
// into a new object like various previously existing libraries do.
opts = extend({}, GetDefaults(), opts);
var totalAccumulatorInitialValue = opts.totalAccumulatorInitialValue;
var totalAccumulator = opts.totalAccumulator;
var parentsAccumulatorInitialValue = opts.parentsAccumulatorInitialValue;
var parentsAccumulator = opts.parentsAccumulator;
var childrenGetter = opts.childrenGetter;
/// etc.
...
}
In javscript we can do this
var text = "the original text";
text+=";Add this on";
If a library has a function already defined (e.g)
//In the js library
library.somefunction = function() {...};
Is there a way to add something on so that I can have two functions run?
var myfunction = function() {...};
Something like:
library.somefunction += myfunction
So that both myfunction() and the original library.somefunction() are both run?
You can use this kind of code (leave scope empty to use default scope):
var createSequence = function(originalFn, newFn, scope) {
if (!newFn) {
return originalFn;
}
else {
return function() {
var result = originalFn.apply(scope || this, arguments);
newFn.apply(scope || this, arguments);
return result;
};
}
}
Then:
var sequence = createSequence(library.somefunction, myFunction);
I think what you want to create is a Hook (function) - you want to call library.somefunction but add a bit of your own code to run before. If that's the case, you can make your myfunction either call or return the library function after it's done with your bit of code.
var myfunction = function() {
// your code
// ...
return library.somefunction();
}