JavaScript has two scopes: global and local. A variable that is declared outside a function definition is a global variable, and its value is accessible and modifiable throughout your program. A variable that is declared inside a function definition is local.
var a = 1; //global variable, becomes a property of window object also
function () {
var b = 2; // local variable
c = 3; //implicit global variable, will cause Error in strict mode
}
console.log(a); //1
console.log(window.a); //1
console.log(b); //undefined
console.log(window.b); //undefined
console.log(c); //3
console.log(window.c); //3
There are many variables initially defined in global scope
You can accidently overwrite something
Global variable will not be eligible for collection until the global namespace loses scope.
Always beware that someone will declare the variable with the same name as yours and the app will work incorrectly
Creates local scope and executes it immediately
//Global scope is here
(function(){
//This is the local scope of the function, no globals are created
var hello = 'Hello World!'
console.log(hello);
//Function is immediatly executed after creation
})();
The most commonly used design pattern and widely accepted in a number of large projects such as jQuery, Dojo, ExtJS and YUI.
(function( window, undefined ) {
function MyModule() {
// `this` refers to the instance of `MyModule` when created
this.myMethod = function () {
alert( 'my method' );
};
}
// expose access to the constructor
window.MyModule = MyModule;
})( window );
// example usage
var myModule = new MyModule();
myModule.myMethod(); // alerts "my method"
The only difference from the module pattern is that this pattern was engineered as a way to ensure that all methods and variables are kept private until they are explicitly exposed.
var myModule = (function( window, undefined ) {
function myMethod() {
alert( 'my method' );
}
// explicitly return public methods when this object is instantiated
return {
someMethod : myMethod
};
} )( window );
// example usage
MyModule.myMethod(); // undefined
MyModule.someMethod(); // alerts "my method"
EcmaScript 3 was released in December 1999 and EcmaScript 5 in December 2009. None of them contained the out of the box implementation of the modules. Module pattern interpretation differs from project to project, modules are hard to reuse.
The CommonJS group defined a module format to solve JavaScript scope issues by making sure each module is executed in its own namespace. This is achieved by forcing modules to explicitly export those variables it wants to expose to the “universe”, and also by defining those other modules required to properly work.
To achieve this CommonJS give you two tools:
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
var add = require('math').add;
module.exports = function(val) {
return add(val, 1);
};
var inc = require('increment');
var a = 1;
inc(a); // 2
CommonJS modules' 'require()' function call will block the execution until the required module will be loaded into the memory and initialized. This approach cannot be used in the browsers, that's why CommonJS modules were applied to the node.js platform and become a standard there for a long time.
If the mountain will not come to Mohammed, Mohammed must go to the mountain
Browsers don't have the "require()" method defined, but Node.js does. With Browserify you can write code that uses require in the same way that you would use it in Node by bundling up all of your dependencies into single JavaScript file.
Install Browserify from NPM
npm install -g browserify
Compile CommonJS module with all it's dependencies into bundle
browserify main.js --outfile=bundle.js
Not all developers were ready to build their frontend. Not all of the projects have Node.JS as a backend.
The API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded. This is particularly well suited for the browser environment.
define([], function() {
return {
add: function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
});
define(['math'], function(math) {
return function(val) {
return math.add(val, 1);
};
});
require(['increment'], function(increment) {
var a = 1;
inc(a); // 2
});
First version of AMD API started on the CommonJS wiki as a transport format, as Modules Transport/C, but it changed over time to also include a module definition API.
Consensus was not reached. The API was transferred over to its own wiki and discussion group.
The UMD pattern typically attempts to offer compatibility with the most popular script loaders of the day (e.g RequireJS amongst others). In many cases it uses AMD as a base, with special-casing added to handle CommonJS compatibility.
It is possible to create UMD modules using Browserify:
browserify module.js --outfile=myModule.js --standalone
Waiting for out of the box module support in JavaScript
The ES2015 (former ES6, ES.Next, Harmony) brought the native modules support to the JavaScript among the many other innovations.
export function add() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
import { add } from 'math';
export default function(val) {
return add(val, 1);
};
import inc from 'increment';
var a = 1;
inc(a); // 2
So where the modules will work?
Modules | In browser | In Node.JS | In browser (build) | In Node (build) |
---|---|---|---|---|
CommonJS | - | + | + | |
AMD | + | - | + | + |
UMD | + | + | + | |
ES2015 | - | - | + | + |
browserify src/index.js -t babelify | uglifyjs > public/bundle.js