Let's say I have a namespace like that:
var myNamespace = {
foo: function() {
},
bar: function() {
}
};
What is the best way to split this code into files defining foo and bar separately?
I'm not worried about loading time - I'll concatenate it back into one file before deployment.
At the start of each file:
if(myNameSpace === undefined) {
var myNameSpace = {};
}
File 1:
myNamespace.foo = function()...
File 2:
myNamespace.bar = function()...
// File1:
// top level namespace here:
var myNamespace = myNamespace || {};
// File2:
myNamespace.foo = function() {
// some code here...
}
In each file follow this pattern:
(function(nameSpace) {
nameSpace.foo = function() { ... };
})(window.nameSpace = window.nameSpace || {});
This way load ordering is unimportant.
Simple define in seperate files like this:
File 1:
var myNamspace = {};
File 2:
myNamespace.foo = function()...
File 3:
myNamespace.boo = function()...
Just make sure you load the files in the right order.
(function (NS) {
NS.Uber = function Uber() {
this.super = new NS.Super(); // yes, it works!
}; //
}(NS = NS || {}));
// ------------- other file -----------------
(function (NS) {
NS.Super = function Super() {
this.uber = new NS.Uber(); // yes, it will also work!
}; //
}(NS = NS || {}));
// -------------- application code ------------
var uber = new NS.Uber();
console.log(uber.super);
var super = new NS.Super();
console.log(super.uber);
Related
This related to javascript code. My application has many sub applications that are sometimes used more then once on a page. An example would be an application that allows the user to search for some data and displaying the search results. This application my be used in multiple places on a page to search for different types of data.
Each sub application typically includes many javascript modules each in a separate file. I have experienced with many different module patterns to try to create a separate instance of multiple modules/files but with no success. There is much advice online how to create multiple instances of objects, using factory pattern etc but I have not been able to make it work with the name space structure and module pattern my application. See example below.
The question is how can you create multiple independent instances of SubAppA including all its sub modules.
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.Config = (function () {
function A () { ... };
function B () { ... };
return {
A : A,
B : B
}
})();
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.GetData = (function () {
function A () { ... };
function B () { ... };
return {
A : A,
B : B
}
})();
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.DisplayData = (function () {
etc.....
Many thanks in advance
--- Additional information after solution proposed by MikeM -----
Thanks MikeM, you answer gave me a better understanding but when trying to implement it using my existing name space structure, I can't get the modules to communicate with each other. I tried the following:
//Solution $S.AS - New file
var $S = $S || {};
$S.AS = $S.AS || {};
$S.AS.DataStore = function () {
var _SomeVar = "Default";
function SetVar (Data) {
_SomeVar = Data;
};
function GetVar () {
return _SomeVar;
};
return {
SetVar : SetVar,
GetVar : GetVar
}
};
//Solution $S.AS - New file
var $S = $S || {};
$S.AS = $S.AS || {};
$S.AS.ManageData = function () {
function StoreData (Data) {
console.log($S.AS.DataStore); //outputs f ()
//Does now work since DataStore is now a function
//$S.AS.DataStore.SetVar(Data);
$S.AS.DataStore().SetVar(Data);
};
function DisplayData () {
//Does now work since DataStore is now a function
//var SomeVar = $S.AS.DataStore.GetVar();
//Does not work, still outputs "Default"
var SomeVar = $S.AS.DataStore().GetVar();
console.log(SomeVar);
};
return {
StoreData : StoreData,
DisplayData : DisplayData
}
};
//Solution $S.AS - New file - The contructor function for AS
var MainApp = MainApp || {};
MainApp.S = MainApp.S || {};
MainApp.S.AS = MainApp.S.AS || {};
MainApp.S.AS = function () {
this.DataStore = $S.AS.DataStore();
this.ManageData = $S.AS.ManageData();
//additional modules
};
//Main/Page specific code - creating the different instances
MainApp.S.AS_1 = new MainApp.S.AS();
MainApp.S.AS_2 = new MainApp.S.AS();
//Attemps to store and retrieve data
//Stores AAA in the DataStore module
MainApp.S.AS_1.ManageData.StoreData("AAA");
//Stores BBB in the DataStore module
MainApp.S.AS_2.ManageData.StoreData("BBB");
//Not working, ouputs: "Default" (Desired result is "AAA")
MainApp.S.AS_1.ManageData.DisplayData();
//Not working, ouputs: "Default" (Desired result is "BBB");
MainApp.S.AS_2.ManageData.DisplayData();
I think I understand why "Default" is output (the call is made to the original variable stored at page load) but not how to fix it.
For context, I have a custom php script that concatenates all the JS files required for a page and then adds them as a single tag to the page. I thought this would speed up script loading, in particular since most of my pages will have 50+ JS files/modules. A typical Name space structure for a page will look as follows (but with a lot more modules):
MainApp = {
//Page specific or utility modules
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
//Resulable applications consisting of multiple modules
SubAppA : {
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
},
SubAppB : {
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
}
}
I was hoping that I can somehow preserver this structure to avoid the risk of conflicting module names. I am happy to change the structure of the modules themselves (e.g. from IIFE to something else) to get an solution to the question.
Thanks
Thanks MikeM, it is now working, very helpful! Yes I am aware of that I need to look at ES modules closer. I learned to code recently to test an idea after working in a completely different field for 17 years so some shortcuts had to be made ...
Here is a write up of my implementation step by step in case it helps someone else that is not too familiar with Javascript modules.
The objectives of the question were to:
Enable multiple instances of an application to exist on a page where each application consists of multiple modules
Enable the modules to call methods in other modules
Make it easy to instantiate (create a new version) of the application
Some things to consider in relation to below solution:
Rather than static calls to methods in other module (e.g. ReuseApp.App1.Display.DisplayData(Data) each module stores an internal reference of the top object of the newly created instance of the application (e.g. _App.Display.DisplayData(Data).
Module are created without the immediately evoked feature (i.e. no IIFE pattern).
A construction function referencing all required module are required. This function will send the newly created object (this) into each module e.g. this.Config = ReuseApps.App1.Config(this);
Each module to take this reference as a parameter (App) and store it within the module (_App). _App will be used when calling other module methods.
Step by step by step guide:
STEP A: Create modules using the following pattern (disregard multi level namespaces if not needed):
//Separate file e.g. Config.js
const ReuseApps = ReuseApps || {};
ReuseApps.App1 = ReuseApps.App1 || {};
ReuseApps.App1.Config = function (App) {
let _App; //Used to call other module methods
let _Settings = {};
function Init (Settings) {
_Settings = Settings;
//Configure app e.g. store element refs, add event handlers etc
var Data = GetDataFromSomeWhere();
//Call another module using the _App reference
_App.Display.DisplayData(Data);
}
_App = App;
Return {
Init : Init
}
}
//Separate file e.g. Display.js
const ReuseApps = ReuseApps || {};
ReuseApps.App1 = ReuseApps.App1 || {};
ReuseApps.App1.Display = function (App) {
let _App; //Used to call other module methods
function DisplayData (Data) {
//Display Data in DOM
}
_App = App;
return {
DisplayData : DisplayData
}
}
STEP B: Create the construction function required to create a new instance of application
//can be in separate file e.g. app1_create.js
function App1Create () {
this.Config = ReuseApps.App1.Config(this);
this.Display = ReuseApps.App1.Display(this);
//etc more modules …
}
STEP C: Creating a separate instance of above application in the main code
//Create new instance using constructur function
//(Assumes the MainApp namespace exists already)
MainApp.ViewDataList = new App1Create();
//If application needs to be initiated
var Settings = { some settings };
MainApp.ViewDataList.Config.Init(Settings);
A simple example of one way of creating "multiple independent instances of SubAppA including all its sub modules", where the modules are defined in multiple files:
// test.js
import { MainApp } from './mainApp.js';
import { SubApp } from './subApp.js';
MainApp.SubAppA = new SubApp();
console.log(MainApp.SubAppA.Config.A()); // 1
MainApp.SubAppB = new SubApp();
console.log(MainApp.SubAppB.Config.B()); // -1
// subApp.js
import { config } from './config.js';
import { getData } from './getData.js';
export function SubApp() {
this.Config = config();
this.GetData = getData();
}
// config.js
export function config() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
As a single file:
const MainApp = {};
function SubApp() {
this.Config = config();
this.GetData = getData();
}
function config() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
function getData() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
MainApp.SubAppA = new SubApp();
console.log(MainApp.SubAppA.Config.A()); // 1
console.log(MainApp.SubAppA.GetData.A()); // 1
console.log(MainApp.SubAppA.Config.B()); // 0
MainApp.SubAppB = new SubApp();
console.log(MainApp.SubAppB.Config.B()); // -1
console.log(MainApp.SubAppB.GetData.B()); // -1
console.log(MainApp.SubAppB.Config.A()); // 0
The important difference with your own code is that I have replaced the Immediately-Invoked Function Expressions (IIFE) with normal functions that create closures every time a SubApp is created.
Added in response to your edit:
For the code you added in your edit to work, you need to make sure that you pass a reference to the parent object when you create a new ManageData object:
$S.AS.ManageData = function (owner) {
function StoreData (Data) {
owner.DataStore.SetVar(Data);
};
function DisplayData () {
var SomeVar = owner.DataStore.GetVar();
console.log(SomeVar);
};
return {
StoreData : StoreData,
DisplayData : DisplayData
}
};
// ...
MainApp.S.AS = function () {
this.DataStore = $S.AS.DataStore();
this.ManageData = $S.AS.ManageData(this);
};
I encourage you to use ES modules to structure your code and avoid naming collisions. A single file can be created from a module bundler such as roll-up.js.
I have a custom module and would like to provide a method to initialize it on first require, but directly return an object on subsequent requires.
But the module gets cached when first required and therefore subsequent requires still return the init function instead of returning obj directly.
server.js:
var module = require('./module.js');
var obj = module.init();
console.log('--DEBUG: server.js:', obj); // <-- Works: returns `obj`.
require('./other.js');
other.js:
var obj = require('./module.js');
console.log('--DEBUG: other.js:', obj); // <-- Problem: still returns `init` function.
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = (obj) ? obj : { init: init };
How can I work around that problem? Or is there an established pattern for achieving such?
But I would like to keep obj cached, because my real init does some work I would rather not do on every require.
There are some ways to clear the require cache. You may check here node.js require() cache - possible to invalidate?
However, I think that this is not a good idea. I'll suggest to pass the module which you need. I.e. initialize it only once and distribute it to the other modules.
server.js:
var module = require('./module.js');
var obj = module.init();
require('./other.js')(obj);
other.js:
module.exports = function(obj) {
console.log('--DEBUG: other.js:', obj); // <-- The same obj
}
module.js:
var obj = null;
var init = function() {
obj = { 'foo': 'bar' };
return obj;
};
module.exports = { init: init };
I'm running into a really frustrating problem in Node.js.
I'll start with what I'm doing.
I'm creating an object in a file and then exporting the constructor and creating it in other files.
My objects are defined like so:
File 1:
var Parent = function() {};
Parent.prototype = {
C: function () { ... }
}
module.exports = Parent;
File 2:
var Parent = require('foo.js'),
util = require('util'),
Obj = function(){ this.bar = 'bar' };
util.inherits(Obj, Parent);
Obj.prototype.A = function(){ ... };
Obj.prototype.B = function(){ ... };
module.exports = Obj;
I'm trying to use the object like so in another file
File 3:
var Obj = require('../obj.js'),
obj = new Obj();
obj.A();
I receive the error:
TypeError: Object [object Object] has no method 'A'
however when I run Object.getPrototypeOf(obj) I get:
{ A: [Function], B: [Function] }
I have no idea what I'm doing wrong here, any help would be appreciated.
I cannot reproduce your problem. Here is my setup:
parent.js
var Parent = function() {};
Parent.prototype = {
C: function() {
console.log('Parent#C');
}
};
module.exports = Parent;
child.js
var Parent = require('./parent'),
util = require('util');
var Child = function() {
this.child = 'child';
};
util.inherits(Child, Parent);
Child.prototype.A = function() {
console.log('Child#A');
};
module.exports = Child;
main.js
var Child = require('./child');
child = new Child();
child.A();
child.C();
And running main.js:
$ node main.js
Child#A
Parent#C
The source code is clonable via Git at the following Gist: https://gist.github.com/4704412
Aside: to clarify the exports vs module.exports discussion:
If you want to attach new properties to the exports object, you can use exports. If you want to completely reassign exports to a new value, you muse use module.exports. For example:
// correct
exports.myFunc = function() { ... };
// also correct
module.exports.myFunc = function() { ... };
// not correct
exports = function() { ... };
// correct
module.exports = function() { ... };
I am trying to break my code into modules, and I have problems referencing the other modules of my app.
MYAPP = (function(my_app)
{
var funcs = my_app.funcs;
var module2 =
{
stupid_function = function ()
{
var some_var = "auwesome!";
//let's call something from the other module...
funcs.do_whatever();
};
};
my_app.module2 = module2;
return my_app;
})(MYAPP);
The problem comes when MYAPP.funcs changes. For example, when I initialize it and add new methods... since "funcs" was created inside of the closure, it has a copy of MYAPP.funcs and does not have the new stuff I need.
This is the way "funcs" gets more methods... when I execute the method MYAPP.funcs.init() the MYAPP.funcs is re-written by itself.
var MYAPP = (function (my_app, $)
{
'use_strict';
my_app.funcs = {};
my_app.funcs.init = function ()
{
panel = my_app.dom.panel;
funcs = my_app.funcs;
query_fns = funcs.query;
my_app.funcs =
{
some_method: function () { ... },
do_whatever: function () { ... }
};
};
return my_app;
}(APP, jQuery));
Thanks in advance!!
In case it is interesting for anybody...
The method I am using for moduling is the "tight augmentation" http://webcache.googleusercontent.com/search?hl=es-419&q=cache%3Aadequatelygood.com%2F2010%2F3%2FJavaScript-Module-Pattern-In-Depth&btnG=
Nothing to do with modules or global... the difference is if you are changing object variable points to or what variable is pointing to:
var first = {my:"test"};
var second = first; // second points to object {my:"test"}
first.foo = 42; // updating the object, second points to it and can see the change
first = {my:"other"}; // new object, second still points to old {my:"test", foo:42}
I want to access variables by using
MyNamespace.variable1
that are globally accessible. I believe Drupal does something similar, no?
var MyNamespace = {};
MyNamespace.variable1 = value1;
It's just an object really.
What Drupal does is using the following code:
var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
Drupal.attachBehaviors = function (context, settings) {
context = context || document;
settings = settings || Drupal.settings;
// Execute all of them.
$.each(Drupal.behaviors, function () {
if ($.isFunction(this.attach)) {
this.attach(context, settings);
}
});
};
Drupal.detachBehaviors = function (context, settings, trigger) {
context = context || document;
settings = settings || Drupal.settings;
trigger = trigger || 'unload';
// Execute all of them.
$.each(Drupal.behaviors, function () {
if ($.isFunction(this.detach)) {
this.detach(context, settings, trigger);
}
});
};
// …
Using similar code, you can emulate namespaces using JavaScript.
Also, if you have many JS files that each add a "namespace" or Object into a top level package you can do stuff like this:
ModuleA.js
// if Modules is null, create a new object, else use the currently defined instance
var Modules = Modules || {};
Modules.A = {};
// sample instance variable
Modules.A.instanceVar;
// sample function
Modules.A.myFunc = function(param1, param2) {
// do something
}
ModuleB.js
// if Modules is null, create a new object, else use the currently defined instance
var Modules = Modules || {};
Modules.B = {};
// sample instance variable
Modules.B.instanceVar;
// sample function
Modules.B.myFunc = function(param1, param2) {
// do something
}
Then you can of course just call them as you need them Modules.A.myFunc() or Modules.B.myFunc() or Modules.B.instnaceVar = 20;. So you can encapsulate functions as well as variables.
For my code I like to have a root Object, (i.e ) and then added "classes" (objects) to it so that everything has a nice "package like", "OOP" structure to it.
Just create an object. E.g.:
var MyNamespace = {};
MyNamespace.variable1 = ...