Javascript Modules
Module Pattern
Revealing Module Pattern
AMD
commonJS
ES6
Javascript
<script src="/jquery.js"></script>
<script>
var $element = $( 'button' );
$element.css({
opacity: 1
});
$button.click( function( event ) {
$element.css({
opacity: 0
});
});
</script>
<script>
var $element = $( 'header' );
$element.css({
background: 'red'
});
</script>Pros
Simple to integrate
Still able to split into separate files
Cons
Leaking globals
No encapsulation
No interoperability
Module Pattern
<script src="/jquery.js"></script>
<script>
var module = (function() {
// Private
var foo = 'foo';
function privateMethod() {
...
}
return {
getFoo: function() {
return foo;
},
publicMethod: function() {
...
}
};
})();
// Error - private methods
console.log( module.foo );
module.privateMethod();
// Accessing public API
console.log( module.getFoo() );
module.publicMethod();
</script>
<script src="/jquery.js"></script>
<script>
var module = (function( $ ) {
// Private
var $foo = $( '#foo' );
function privateMethod() {
$foo.css({ background: '#d4d6d7' });
}
return {
publicMethod: function() {
privateMethod();
}
};
})( jQuery );
// Error - private method
console.log( $foo );
module.privateMethod();
// Accessing public API
module.publicMethod();
</script>
<script>
(function( root ) {
var privateFoo = 'foo';
var module = {
create: function() {
return {
publicMethod: function() {
module.privateMethod();
console.log( privateFoo );
}
}
},
privateMethod: function() {...}
}
root.module = module.create();
})( this );
</script>
Pros
Encapsulation
Ability to 'reveal' an API
Cons
Limits global leak
Patches and changes, i.e. from private to public, can become problematic as the way in which they are referenced changes
Still leaks globals, which can conflict
Data privacy
Late declaration of additional methods (or extensions) to the module wont have access to private members
Unit testing private variables is impossible
Revealing Module Pattern
<script src="/jquery.js"></script>
<script>
var module = (function() {
var foo = 'foo';
function bar() {...};
// Public API
return {
variable: foo,
publicMethod: bar
};
})();
console.log( module.variable );
module.publicMethod();
</script>
Pros
Syntactically more consistent than standard module pattern
Clear and concise public API declaration
Cons
A late patch to the module object will fail if functions reference each other as any patch will only be applied to the publicly exposed functions, not those used by the module directly.
In short, modules become slightly more fragile.
Asynchronous Module Definition
// script.js
!function() {
define( 'myAwesomeModule',
[
'jQuery',
'lodash'
],
function( $, _ ) {
return {
foo: 'foo',
bar: function() { ... }
};
}
);
require( [ 'myAwesomeModule' ], function( module ) {
module.bar();
console.log( module.foo );
});
}();
Pros
Defines a module structure
Dependency management
Cons
Proper encapsulation and preservation of global, thus eliminating naming conflicts
Highly flexible
Encourages asynchronous loading and allows lazy loading of scripts
Fair amount of boilerplate
Its flexibility means it can be confusing or overly verbose
Is asynchronous script loading really as useful as you might think?
CommonJS
// script.js
var $ = require( 'jQuery' );
var _ = require( 'lodash' );
module.exports = {
foo: 'foo',
bar: function() {...}
};
Pros
Many similar pros to AMD, such as encapsulation and clear definition
Super simple
Cons
Simplicity
Requires a build step to make sense in browser-land without destroying global
ES6 Harmony Modules
// module.js
var privateFoo = 'foo';
export default class Superman extends Man {
constructor( name ) {
this.name = name;
}
get name() {
return this.name;
}
say() {
super();
console.log( 'Hello from', this.name );
}
}
// app.js
import Superman from 'module';
var clark = new Superman( 'Clark' );
Pros
Proper module system
Will likely be available to use as part of a <module> tag
Cons
Simple CommonJS format
Fairly gnarly build steps involved
Most libraries currently dont support ES6 modules, however, there are build step work arounds which will attempt to work out the type of module being imported and load it in a sensible manner. This allows ES6, CommonJS and AMD to be used alongside each other.
Javascript Modules
By Matt Styles
Javascript Modules
- 369