Which design pattern(s) take advantage of JavaScript's hoisting behavior?
Solution 1:
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...
Solution 2:
Here's a use for hoisting:
(function() {
var factorial = function(n) {
if(n == 0)
return 1;
return n * factorial(n - 1);
};
})();
Without hoisting, that wouldn't compile because factorial
wouldn't exist yet inside the function literal. You'd have to declare the variable separately or use a named function.
JavaScript also allows code like the following:
var test = function(b) {
if(b) {
var value = 2;
} else {
var value = 5;
}
console.log(value);
};
With block scoping, you'd have to add another line to declare value
before the if
.
To be fair, this code works because of function scope, not hoisting. And JavaScript could have had function scope without hoisting. Ruby handles this better: Ruby has method scope for variables, but the variables don't exist until you set them:
def test(b)
# unlike JavaScript, value is not accessible here
if b
value = 2
else
value = 5
end
puts value
end
Solution 3:
JavaScript does not have block scope (let's forget about let
for now) and thus any variable declaration is declaring for the entire function, of which JavaScript does have scope.
If you think about it that way, JavaScript hoisting may make more sense.
If you remember about hoisting, it shouldn't be a source of bugs and confusion. It's simply one of those quirks you must understand and remember.
I'm not sure if hoisting is limited to JavaScript. I've never heard of it elsewhere, but that doesn't necessarily mean it doesn't exist in other languages.
Solution 4:
The first two examples in that article are just badly written. Bad code obviously leads to bugs and confusion. Let me give you the refactored versions of these examples. You will see that there is no confusion here...
Example 1 - Original code
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
Example 1 - Refactored code (removed confusion)
var foo = 1;
function bar() {
var foo;
if ( !foo ) {
foo = 10;
}
alert( foo );
}
bar();
The alert displays "10", and it's clear why. No confusion here.
Example 2 - Original code
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Example 2 - Refactored code (removed confusion)
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert( a );
The alert displays "1". Obviously. No confusion here, too.
Solution 5:
"hoisting" is not part of the ECMAScript Standard, but it does say that variable inside a function are declared at the begin of the function regardless of where in the function it is place in the code.
Example
(function() {
alert(myvar); // undefined
var myvar = 'local value';
})();
Internally Javascript would declare myvar before the alert, show the alert, then it would assign myvar to 'local value'.
So Javascript would interpet that code as:
(function() {
var myvar;
alert(myvar); // undefined
myvar = 'local value';
})();
That is why "Java the Good parts" has a guideline that say you should declare variable at the top of your function.
Source: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/
"Please explain if there is a design pattern that actually takes advantage of this language feature." "hoisting" is not a feature but rather a consequence how the Javascript interpreter structure the code since the language uses function-scoping.
"Which design pattern(s) actually take advantage of JavaScript's hoisting behavior? " Answer: None.