I am loading separate .js files into my html page. These files use anonymous functions so that the global scope is not filled with global variables. For example: this is my 'utils.js' file:
(function(window){
var Utils = {
createURL: function() {
console.log("creating url");
}
};
})(window);
My question: if I have several of these .js files, how can they reference each other without using the global scope? As it stands, I can only call this function from within the same utils.js file:
var myUtils = new Utils();
You can create global modules and expose only the needed functions like this...
// In some JS file
var moduleX = (function(window){
var Utils = function(){
};
return {
"Utils" : Utils
};
})(window);
// In a some other JS file
var util = new moduleX.Utils();
Btw, you cannot instantiate a JSON object(Utils in your case). So please change that to a function.
You can use a javascript loader like
require.js
head.js
yepnope
If you don't want to use a loader, maybe you can reduce the global usage to the minimun using a design pattern like the mediator or module.
(function(window){
var app = {};
app.Utils = {
createUrl:function(){}
};
window.app = app;
})(window);
and then you can work with the app like this :
app.Utils.createUrl();
If you don't want to use a third party tool, you can wrap everything into one module by using the following pattern:
//file1
var myModule = (function(window, that){
var myVar = 1;
that.myMethod1 = function(){
console.log("i am module 1");
};
return that;
}(window, myModule || {}));
//file2
var myModule = (function(window, that){
that.myMethod2 = function(){
console.log(typeof myVar); //undefined
that.myMethod1(); //i am module 1
};
return that;
}(window, myModule || {}));
This will ensure that you only have one single global variable. But, you will of course not be able to access local variables of another file.
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
In one of my JS files I include another one. How can I set variables in the included module?
I thought doing something like this would work
var mymodule = require('mymodule.js');
mymodule.myvariable = 'test';
And then in mymodule
this.myvariable === 'test';
But this doesn't work, it's undefined. What are the various options for passing a value into a module? I could just add the variable as a parameter to every function I call in mymodule, but that isn't ideal.
Is there a way to do it without globals, so that I can set the variables independently in various required modules, like this?
var mymodule1 = require('mymodule.js');
var mymodule2 = require('mymodule.js');
mymodule1.myvariable = 'test1';
mymodule2.myvariable = 'test2';
The problem with what you were doing is that you set the variable after importing, but this.myvariable === 'test'; was being called when the module was imported, before your variable was set.
You can have your module export a function and then call the function when you import, passing your variable as an argument.
module.exports = function(myVar) {
var myModule = {
// has access to myVar
...
};
return myModule;
};
When you import,
var myModule = require('myModule')(myVar);
If you use this method, keep in mind that you get a different instance of your module wherever you import, which may not be what you want.
If you want to set values of a module from outside the module, a good option is to have your module export an object with a setter method, and use that to set the value of the variable as a property of the object. This makes it more clear that you want this value to be settable, whereas just doing myModule.myVar = can set you up for confusion later.
module.exports = {
myVar: null,
setMyVar: function(myVar) {
this.myVar = myVar;
},
...
};
In this case you're accessing the same instance of the model wherever you import it.
Edit in response to comment
In the first option you show where you get a different instance each
time, how can I export multiple functions that each share the same
myVar? If that module exports 5 functions each that need myVar, can I
set it in one place like at import time rather than passing it into
each function?
Not entirely sure if I understand what you're describing, but you could do something like this:
module.exports = function(myVar) {
var modules = {};
modules.someModule = {...};
modules.anotherModule = {...};
...
return modules;
};
Each of these sub-modules would have access to the same myVar. So you would import as above and the result would be an object containing each of your five modules as properties. I can't say whether this is a good idea, it's getting pretty convoluted, but maybe it makes sense for your situation.
NodeJS require() will always load the module once so you will need to implement scoping into your module where different instances of the module can exist with their own internal state.
You can implement your module as a JS class like:
var MyModule = function(){};
MyModule.prototype.someFunction = function(params){
this.someVar = params;
}
MyModule.prototype.anotherFunction = function(key, value){
this[key] = value;
}
module.exports = MyModule;
Then in your code;
var MyModule = require('MyModule');
someModule = new MyModule();
// treat someModule like an object with its getters/setters/functions
Should work just fine. Here is a working example:
index.js
var module = require('./module.js');
module.myvar = 'Hello world';
module.test();
module.js
module.exports = {
test: function() {
console.log('var is', this.myvar);
}
};
Keep in mind if you use this in a closure that the scope isn't any longer the module itself. So that could be your problem.
Can you show me the part of the module code where you use this?
This is a module named StrUpperCase.js
exports.StrUpperCase = function(str) {
return str.toUpperCase();
}
In app.js:
var str = "Welcome World...";
const SUC = require('./modules/StrUpperCase');
console.log(SUC.StrUpperCase(str));
if I have a javascript file with the contents:
(function() {
return function (foo) {
return foo + "bar";
};
}());
is it possible to capture the return value from that file in a variable somehow? I'm assuming the function is returned to the auto instantiating parens and then garbage collected, but I'm not sure.
As an aside, I'm trying to expose a browserified collection of node modules to the window for testing purposes (I realize there are probably other methods for going about this, but I'm curious about this one).
Files that are included with browserify (or other CommonJS compatible system) can expose methods or values to the requiring file via module.exports. module.exports is returned from the require() statement.
Take this example:
index.js
var myClass = require("myClass");
myClass.js
module.exports = (function() {
return function (foo) {
return foo + "bar";
};
}());
index.js now has access to the function that is built in myClass.js and can use it as:
index.js
var myClass = require("myClass");
// expose the class to the global scope
window.myClass = myClass;
var result = myClass("foo ");
so the var result would have the value "foo bar".
I'm trying to create a namespace for my backbone app so I can make calls globally.
Normally, I'd just do it like this:
var myNamespace = window.myNamespace || {};
myNamespace.SomeView = Backbone.View.extend(..);
Not sure how to achieve this using require js
You can do the same in your require or define calls, window's still there (if you work in browsers).
// views/app.js
define(['router', 'views/main-view'], function (router, mainView) {
var App = function () { /* main app module */ };
// do your "global" export
window.App = App;
return App;
});
// views/header-view.js
define(['views/app', 'models/user'], function (App, User) {
// your header view code here
// note that you have access to `App` already in a closure
// but you can still talk to it by doing
globalAppReference = window.App;
globalAppReference === App; // true
});
The question is why would you need it? Ideally all your modules would be defined with requireJS, so you don't need to refer to them through global object.
I have following structure for my client;
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
var logger = {};
var utilityObject1 = {};
var utilityObject2 = {};
var mainObject = {};
mainObjectList.push(mainObject);
},//init
someOtherMethods:function(){}
};//globalObject
return globalObject;
})();
with my client I can say
myObject.init(5);
and create a new structure.
My problem is I have a lot of utility objects inside init function closure (logger, utilityObject1, utilityObject2..). My total file exceeded 1000 lines so I want to separate all utility objects into different files to have a better project. for example I could separate logger, utilityObject1 , utilityObject2 to their own files. the problem is since objects are in closure I cannot just add them to main object in separate files. so I thought of following injection method.
//start of file1
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
var logger;
var utilityObject1 = {};
var utilityObject2 = {};
var mainObject = {};
mainObjectList.push(mainObject);
},//init
someOtherMethods:function(){},
injectLogger:function(creator){
this.logger = creator();
}
};//globalObject
return globalObject;
})();
//start of file2
myObject.injectLogger(function(){return {};});
That way I can separate my files for development. but in production I can concatenate files to have one file. But I have some problems with this design. I just added an accessible injectLogger function into myObject. and my logger cannot use other local variables in closure now(I have to pass them to creator object now). My question is is there any other way to separate that kind of code into files. (maybe an external utility.)
I like to use google's closure compiler http://code.google.com/closure/compiler/
If you don't want to use something like that, you might try this sort of thing: (Make sure you load globalObject.js first to define the variable).
//globalObject.js
var globalObject = function() {
}
//init.js
globalObject.prototype.init = function() {
this.utilityFunction();
//do something with utilityObject1
this.utilityFunction(this.utilityObject1);
}
//utilityFunction.js
globalObject.prototype.utilityFunction= function() {}
//utilityObject1.js
globalObject.prototype.utilityObject1 = {};
//main.js
var myObject = new globalObject();
myObject.init();
You could then overwrite the function by doing something like this:
//main.js
var myObject = new globalObject();
myObject.utilityFunction = function() {
//new function
}
myObject.init(); // This will then use the new utilityFunction method you just set.
As I understand it, you want to have some lexical variables that all of your modules close over, but you want to keep the code for the various modules in different files.
One way to achieve this exact behavior is to create a single Javascript file by concatenating the module definitions together:
Header.js-partial
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
Logger.js:
function Logger() { this.enabled = true; }
Logger.prototype.log = function() {
if (window.console && window.console.log) {
return window.console.log.apply(window.console.log, arguments]);
}
}
etc.
Add other module files as desired. They can reference lexical variables.
Footer.js-partial
}// end init
}; // end globalObject
return globalObject;
})();
In the end you need a script that will concatenate all of these files together into a single js file. There is no other way to get truly lexical variable access in pure Javascript.
A superior alternative
That said, this technique is ripe for confusion and I don't recommend it. Closures are generally meant for closing over local variables, not program-wide variables. If you use a lexical variables declared 1000 lines ago, you will spend some amount of time tracking down where all your variables were declared when running your program. Instead you should probably enclose private, 'global' data in the globalObject. For example, store mainObjectList in globalObject.mainObjectList and reference that in module files.
I recommend a solution like that described by nemophrost. Each file should be valid javascript on its own.
You could use command-line PHP to serve as a preprocessor to combine your files. For example, main.js.php could look like this:
(function() {
<?php require('foo.js.php');?>
})();
and then run the command php main.js.php > combined.js when you want to produce an output file usable for minification and deployment.
This has the advantage that you can load main.js.php onto a server to test a new version of the code without recompiling. You can just put a line at the very beginning of main.js.php to get PHP to send the correct MIME type:
<?php header('Content-type: text/javascript');?>
The way I deal with this problem to check to see if the global object exists and if not create it. This way the order isn't important.
// file 1
var Global_Obj = Global_Obj || {}; // creates empty global object
Global_Obj.An_Obj = { /* stuff */ };
// file 2
var Global_Obj = Global_Obj || {}; // uses created global object
Global_Obj.Another_Obj = { /* stuff */ };