Variable hoisting
One of the simplest uses of hoisting is variable hoisting. If we didn't have variable hoisting, this would throw a ReferenceError
:
var bar = foo;
var foo;
That doesn't seem immediately useful, but it allows us to do things like this:
var myCoolJS = myCoolJS || {};
This basically means what it looks like: myCoolJS
is myCoolJS
if it exists, or a new object if it doesn't. The second myCoolJS
doesn't throw a ReferenceError
if myCoolJS
didn't already exist, because this variable declaration is hoisted.
This saves us from doing an awkward typeof myCoolJS != 'undefined'
check.
Function hoisting
Function hoisting can be especially useful when combining multiple scripts into one. For example, I've created a lightweight build-time implementation of CommonJS modules. This provides the same module
, require
, and exports
features that are found in node.js. I built the tool to allow required modules to be composed of multiple files. For example, require('/foo')
could result in a module composed of two files, foo.js
(the "body file") and foo.h.js
(the "header file").
This allows the "body file" to have no knowledge of the free variables provided by the CommonJS modules environment; all of that is handled in the header. This makes code reusable and easy to test without building. However, since the headers are prepended to the body, we leverage function hoisting in the body file to allow exports in the headers. For example:
// dom.h.js
var util = require('util').util;
exports.css = css; // we can do this because "css" is hoisted from below
// ... other exports ...
...
// dom.js
function css(){}; // this would normally just be an object.
css.hasClass = function(element) { ... };
css.addClass = function(element) { ... };
// ...other code...