Given a namespaces ns used in two different files:
abc.js
ns = ns || (function () {
foo = function() { ... };
return {
abc : foo
};
}());
def.js
// is this correct?
ns = ns || {}
ns.def = ns.def || (function () {
defoo = function () { ... };
return {
deFoo: defoo
};
}());
Is this the proper way to add def to the ns to a namespace? In other words, how does one merge two contributions to a namespace in javascript?
If abc.js comes before def.js I'd expect this to work. If def.js comes before abc.js I'd expect ns.abc to not exist because ns is defined at the time.
It seems there ought to be a design pattern to eliminate any uncertainty of doing inclusions with the javascript namespace pattern.
I'd appreciate thoughts and input on how best to go about this sort of 'inclusion'.
Thanks for reading.
Brian
That would certainly work. Keep in mind, though, that source order will affect your implementation: if def.js ever winds up included before abc.js, your definition of foo and ns.abc will never be executed.
Take a look at YUI's old namespace function for an example: they make sure either use the existing object or a new object initialization, probably for that reason above.
It might very well help you to keep your modules separate with something like this:
ns = ns || {};
ns.abc = function(){ ... }();
and
ns = ns || {};
ns.def = function() ... }();
That way, each is a separate module, source order doesn't matter, and each has access to its own closure as you have in your example.
As a matter of interest, I discovered AMD and RequireJS and started using that.
Related
I'm developing a Node.js application that contains a game engine, and I basically have this pattern in my engine:
A.js
var B = require('./B');
var A = module.exports = function () {
this.b = new B;
console.log(B.staticBar)
};
A.staticFoo = 'foo';
B.js
var A = require('./A');
var B = module.exports = function () {
console.log(A.staticFoo);
};
B.staticBar = 'bar';
So I want both A.staticFoo to be accessible in B.js and B.staticBar in A.js.
Any idea how to do that?
Thanks
EDIT : actually my static variables are config values, so another solution would be to group them into a config.js file and require that file in every other file, but I find it more elegant to define config variables directly as static members of related classes. Hope that's clear enough ;)
I would suggest separating your static state into a third module... By decoupling state from your module, you can operate either independently.
state.js
//state.js - changed by other modules...
module.exports = {
staticFoo: null,
staticBar: null
};
a.js
//a.js
var state = require('./state');
exports = module.exports = fnA;
...
function fnA() {
console.log(state.staticBar);
}
b.js
//b.js
var state = require('./state');
exports = module.exports = fnB;
...
function fnB() {
console.log(state.staticFoo);
}
Another example mentions something akin to dependency injection... given how modules work in JS, and that you can override for testing with proxyquire and the like, I tend to prefer the simpler requires structure over dealing with DI/IoC in JS as it muddles your project code.
I also like to do my requires, then my exports, then any methods within that module, usually just one method in a module.
It would depend on the architecture of your code. BUT, working with other people's code is always different of course.
The best choice is to separate your code into smaller module(s). If they're referencing each other it can challenging to build tests especially when the code grows.
OR
If that's not possible you could always remove coupling through the use of references.
B.js
var _A;
exports.setA = function(ref) {
_A = ref;
};
var B = exports.B = function () {
console.log(_A.staticFoo);
};
And use B.setA(A) to make sure B has a reference to use A.staticFoo
I understand that using closures (IIFE) is the best practice as it prevents polluting the global namespace. However, when I added the closures to my files, it prevented my 2nd file (controllers.js) from reading the first file (models.js). To give you an idea, here's what they look like:
models.js
;(function() {
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})();
controllers.js
;(function() {
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
Now that I've added closures on them, I'm getting an error that searchResult is undefined in controllers.js -- because it can't see that it exists in the models.js. How do I get it to understand that it exists in the other file?
P.S. Yes, models.js is added in the HTML file before the controllers.js file.
For them to interact, they have to have some common symbol. You have a couple of choices:
Do it yourself (using a single global variable)
Use some kind of library that does it for you (using [ideally] just a single global symbol)
Do it yourself a different way that requires no global common symbol at all
Do it yourself
The DIY version is, typically, that you have a single global, for your entire app, which your various modules add properties to.
So for instance:
models.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
MyApp.searchResult = searchResult;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})(this);
That works because in loose mode, this at global scope is the global object (window on browsers). We pass it into the IIFE as the argument globals, and then either use or create a property on it called MyApp, and add searchResult to it as a property.
controllers.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
function storeSearchResults(jsonObj) {
var instance = new MyApp.searchResult(jsonObj.data[i]);
/* Do more */
}
})(this);
We do the same thing, except that controllers.js is expecting that models.js has already been run. Although we still do the var MyApp = globals.MyApp = globals.MyApp || {}; bit, the new MyApp.searchResult would of course fail if models.js hadn't been run.
There are probably a dozen syntactic variations on this theme, this is just one of them.
Use some kind of library that does it for you
Your other option is to use a library like RequireJS (the one global symbol there is require, and it's a function) or any other asynchronous module definition lib.
Do it yourself another way
Another DIY option gets rid of globals entirely, you don't even need a single global.
To do that, your individual files don't have the IIFE (although they can use ones for things they don't want to share with other files):
;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
controllers.js:
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
Then you use a minifier to combine your scripts and wrap them in one big IIFE. You might have pre.js:
(function() {
and post.js:
})();
Then the minifier creates app.js by combining pre.js + models.js + controllers.js + post.js. The end result (un-minified and formatted here for readability) is:
(function() {
;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
I called this DIY, but I wouldn't be surprised if there were tools to help with it.
Events and listeners passing and receiving data.
I don't use globals.
However I don't know how to use events in raw javascript or if data passing can be done. I use jquery/node which allow for passing data and just works beautifully.
I have module pattern done like this:
var A = (function(x) {
var methodA = function() { ... }
var methodB = function() { ... }
var methodC = function() { ... }
...
...
return {
methA: methodA,
methB: methodB
}
})(window)
This code let's me call only methA and methB() on A which is what I want and what I like. Now the problem I have - I want to unit test it with no pain ot at least with minimal efforts.
First I though I can simply return this but I was wrong. It returns window object.(can someone explain why?).
Second - I found solution somewhere online - to include this method inside my return block:
__exec: function() {
var re = /(\(\))$/,
args = [].slice.call(arguments),
name = args.shift(),
is_method = re.test(name),
name = name.replace(re, ''),
target = eval(name);
return is_method ? target.apply(this, args) : target;
}
This method let's me call the methods like this: A.__exec('methA', arguments);
It is almost what I want, but quite ugly. I would prefer A.test.methA() where test would never be used in production code - just for revealing private methods.
EDIT
I see people telling me to test the big thing instead of the small parts. Let me explain. In my opinion API should reveal only the needed methods not a bunch of internal functions. The internals because of their small size and limited functionality are much easier to test then test the whole thing and guess which part gone wrong.
While I may be wrong, I would still like to see how I could return references to all the methods from the object itself :).
Answer to your first question(you return this, but it returns window, not the object you wanted): in javascript this inside the function returns global object unless this function is a method of the object.
Consider next examples:
1) this points to the global object ():
function(){
return this;
}
2) this points to the object:
var obj = {
value: "foo",
getThisObject: function(){
return this;
}
}
Your case is example #1, because you have a function, that returns an object. This function is not a method of any object.
The best answer to your second question is to test only public methods, but if
that is so important for you, I can propose next:
create your modules dynamically on server side.
How it works:
create separate scripts for functionality you want;
create tests for these separate scripts;
create method that will combine scripts into one however you want;
to load script, reference to the combining scripts method.
Hopefully, it can solve your problem. Good luck!
Why not use namespaces to add your modules and public methods to js engine. Like this:
window['MyApp']['MODULE1'] = { "METHOD1" : {}, "METHOD2" : {}};
I write modules like this Sample module in JavaScript.
And test it like this: Simple unit testing in JavaScript
The use of eval() is generally not good idea.
I have a some JavaScript with a complex structure. Because I'm new comer to JavaScript (only understanding some basic concepts) I don't know how to use it properly.
I have two files : Circle.js and Line.js. In Circle.js, I want to use a class object defined in Line.js:
In file Circle.js :
Helper.using('py.Figures', function (ns) {
ns.Circle = function (params) {
// some additional methods and code here
}
}
And in Line.js is :
Helper.using('py.Figures', function (ns) {
ns.Line2Point = function (params) {
// some addition methods and code here
};
}
In Figures.Circle, in ns.Circle I want to use Line2Point but I don't know how.
I think it should be :
line = new ns.Line2Point(params);
But It seem doesn't work.
According to Helper Class, ns will point to helper.using, in this case py.Figures. Does it mean, ns is the same object/reference in both the files?
I don't think this is doable in Javascript directly across files. If they are part of the same namespace you could share some 'global' objects to achieve this have the line2points and circles attach themselves to that global object:
Ex:
var myShapesNameSpace = {};
Circle.js:
(function(){
var circle = {};
circle.method1 = function(){...}
circle.method2 = function(){...}
myShapesNameSpace.Circles = circle;
})(window.myShapesNameSpace = window.myShapesNameSpace || {}); //check if namespace object exists. Else create a new blank one.
Line.js:
(function(){
var line= {};
line.method1 = function(){...}
line.method2 = function(){...}
myShapesNameSpace.Lines= line;
})(window.myShapesNameSpace = window.myShapesNameSpace || {});
Now you can check for the existence of myShapesNameSpace.Circles or .Lines and call the corresponding methods accordingly.
You can include files in javascript and reference objects across files unless they are exported in some global form either via window or your define global
Welcome to Javascript, the shit parts. Require.js was designed precisely for this because the creators of JS, well, I guess thought that everyone would write every program in one file.
RequireJS
It was designed for web use but can be used elsewhere too (locally, with Node, etc.)
The problem I have is that there are a set of variable values / properties in one file and a library in another file. I have started refactoring the code but still need to keep variable values(dynamic) and library(static) differently.
I am using namespacing and overall want only one global namespace.
The problems I have at the moment:
1. How can I still keep one global namespace
2. What is the best way to read the values from one file and use it in the library present in another file.
e.g I came up with something like
//File ONE with values
var main.dynamicvalues = (function(){
var a = 10,
b = 20,
c = 30;
return {
a:a,
b:b,
c:c
}
}());
//File TWO with core Library
var main.library = (function(){
//Various Private functions that need to use a,b,c variables from above main.dynamicvalues namespace
return {
//Public functions again need to use a,b,c from above namespace.
}
}());
Is there a way I can have a pattern so that I keep only one global namespace and can refer to variables directly without having to use maincode.values.a, maincode.values.b, maincode.values.c or something like this in maincode.library.functions
Thanks
Sparsh Gupta
This approach is a little better, but it's not exactly what you're looking for.
var main = {};
main.dynamicvalues = (function() {
// same as before
})();
main.library = (function(dyn){
// use dyn.a, dyn.b etc
return {
// same in here
}
}(main.dynamicvalues));
Create a new file (maybe name it something like "common.js") and put the values there.
You can try RequireJS. This will let you do what you want with no global namespace at all (if you'd like to). In addition it will give you non-blocking script loading, easy way to handle dependencies and a build tool.
On the other hand, it can deprive you of the joy of investigating things for your own and better understanding of js architectural patterns.
Your code with RequireJs could have looked like this:
// File one with values, let's name it values.js
define([], function() {
var a = 10,
b = 20,
c = 30;
return {
a: a,
b: b,
c: c
}
})
// File two with library
define([
// load values.js as a dependency
'values'
// what is returned in values.js can be passed as an argument to the callback
], function( values ) {
values.a === 10 // true
})