-
Notifications
You must be signed in to change notification settings - Fork 11
Modules & Namespacing
JavaScript does not natively support namespacing or modules. Instead, everything simply exists in the global context. Not only does this make organizing and compartmentalizing code more difficult, it could lead to collisions between modules that share variable names. Maintaining unique variables is possible with smaller applications, but can be tedious as a project grows and relies upon other third-party scripts or packages. With bigger applications it is useful to implement a more robust method of avoiding potential collisions. There are many ways to implement namespacing in JavaScript.
See the Namespacing module pattern section below for details on the chosen implementation.
The following outline summarizes the various modules that comprise the LineExtractionApp application.
-
Utils [module]: General utility classes/methods etc.
- Generic Helpers [module]:
- Event Dispatcher [module]: Provides methods for subscribing/publishing events.
-
Data [module]: assist in the instantiation and storage of various data point representations.
- Sensor Reading [class]: An individual data point reading from the sensor. Includes both polar and Cartesian representations.
- Scan File [module]: Read in data points from a json object
- Data Playback [module]: Controls the playback of scan data
-
Perception [module]: assist in perception tasks for 2D lidar scans
- Primitive Extraction [module]: extract primitives from scan data.
- Line Extractor [class]: extracts lines from a set of sensor readings
- Sensor Reading Pre-Processor [class]:
- Line Post-Processor [class]:
- Primitive Extraction [module]: extract primitives from scan data.
-
Plotting [module]: Structures relevant ot plotting 2D graphs of sensor data
- Graph Manager [class]: Manages the graphs which display data
-
Processing [module]: assist in processing 2D lidar data
- Point 2D Utils [module]: operations with basic 2D Cartesian point objects
- Sensor Reading Utils [module]: operations with sensor reading objects.
- Filtering [module]: assist in filtering 2D lidar data
The file structure for these modules is as follows:
-
js
: the source code for the application-
components/
:-
example-module-X.js
: the implementation for hypothetical moduleX - ...
-
-
namespace.js
: defines the application namespace + structure of components/modules
-
The LineExtractionApp application uses a module pattern for namespacing to avoid global collisions. A custom scheme was adopted and used consistently for all modules.
For a given project (such as the LineExtractionApp), a namespace.js
file sits at the root of the project directory. This file instantiates the root of the project's namespace and declares modules that will be filled out in other files. But this just accomplishes the namespacing. Each module then has a file that defines the modules contents (variables, methods, classes, sub-modules) as a self executing function that returns a public API. At the end of the module file is the declaration of the modules public API. The namespacing must be accomplished before the contents of each module have been defined, so the order of script includes must be namespace.js
followed by moduleX.js
.
Example hypothetical namespace.js
for ExampleApp
:
// create the root namespace
let ExampleApp = {};
/************************************************************************************//**
** General purpose namespace method.
** This will allow us to create namespace a bit easier.
****************************************************************************************/
ExampleApp.createNameSpace = function (namespace) {
...
};
/************************************************************************************//**
** Create various namespaces for the ExampleApp
****************************************************************************************/
ExampleApp.createNameSpace("ExampleApp.ModuleX");
...
Example hypothetical ModuleX
for the ExampleApp:
ExampleApp.ModuleX = function ( ) {
//Example private variable
let deg2RadRatio = 3.14/180;
//Example public variable ( made public by public API at bottom )
let two = 2;
//Example private method
let deg2Rad = ( deg ) => {
return deg * deg2RadRatio;
}
//Example public method ( made public by public API at bottom )
let printRadiansFromDeg = ( deg ) => {
let rad = deg2Rad(deg);
console.log(rad);
}
//Example public class (made public by public API at bottom)
let classX = function ( param1 ) {
//instance variables
this.val = param1;
//class method
this.printVal = ( ) => { console.log(this.val);}
}
/************************************************************************************//**
** Public API
* Return all the methods/variables that should be public.
****************************************************************************************/
return {
// public variables
two: two,
// public classes
classX: classX,
// public methods
printRadiansFromDeg: printRadiansFromDeg
}
}();
Then, one can use the module like so:
let myTwo = ExampleApp.ModuleX.two;
let myClassInstance = new ExampleApp.ModuleX.classX( 3 );
console.log( myClassInstance.printVal() ); // 3
ExampleApp.ModuleX.printRadFromDeg( 180 ); // 3.14
To save some keystrokes and avoid ugly extended module names, you can simply hold a local copy like so:
let _X = ExampleApp.ModuleX;
let myTwo = _X.two;
let myClassInstance = new _X.classX( 3 );
console.log( myClassInstance.printVal() ); // 3
_X.printRadFromDeg( 180 ); // 3.14