Closure in JavaScript

Closure is one of those terms you hear thrown around a lot in JavaScript development, but it’s often misunderstood and mistaken for scope. Scope is related and plays an important role in closure, but is not the same thing.

Closure is when a function has access to its original context. Here’s the Mozilla Developer Network’s take on closure:

A closure is a special kind of object that combines two things: a function and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.

An example:

function speak() {
    var greeting = 'hi';
    function saySomething() {
        console.log(greeting);
    }
    saySomething();
}
speak(); //hi

In this example, saySomething is a closure–it is a function that has access to its original context. Put differently, it is a function AND the environment in which it was created because it can access greeting, a variable from the parent function’s scope. greeting is not part of saySomething‘s scope.

Another example:

function speak(name) {
    var greeting = 'hi';
    function saySomething() {
        console.log(name + ' says ' + greeting);
    }
    saySomething();
}
speak('billy'); //billy says hi

In this example, speak defines a variable AND takes an argument. saySomething is still a closure–it can reference variables and parameters that are part of its environment.

A common misconception about closure is that you have to return a function for a closure to exist. This is NOT true. However, let’s expand the existing example by returning the saySomething function instead of executing it:

function speak(name) {
    var greeting = 'hi';
    function saySomething() {
        console.log(name + ' says ' + greeting);
    }
    return saySomething;
}
var billySpeaks = speak('billy');
var nobodySpeaks = speak('nobody');
billySpeaks();   //billy says hi
nobodySpeaks();  //nobody says hi

You’d think name and greeting would only be accessible at the time of execution, but that’s obviously not the case. That’s because local variables and arguments that are in scope at the time a closure is created remain accessible–they are part of the environment.

In the preceding example, speak is a closure that consists of the parameter name, the local variable greeting and the function saySomething when it was created. Therefore, billySpeaks and nobodySpeaks have access to them after execution has finished.

References

More JavaScript

Hoisting in JavaScript

In order to test my understanding of hoisting, closure and scope in JavaScript, I put together a number of exercises (with the help of my colleague Kevin). Each successive exercise builds on the last and the output of the function can be viewed by hovering or clicking the text in the output section below the respective exercise.

What is the output?

(function () {
    var test = 5;

    if (false) {
        test = 7;
    } else {
        console.log(test + 2);
    }
}());
hover for result

7

What is the output?

(function () {
    var test = 5;

    if (false) {
        var test = 7;
    } else {
        console.log(test + 2);
    }
}());
hover for result

7

What is the output? Is test global?

(function () {
    test = 5;

    if (false) {
        var test;
    } else {
        console.log(test + 2);
    }
}());
hover for result

7

What is the output? Is test global?

(function () {
    test = 5;

    if (false) {
        //var test;
    } else {
        console.log(test + 2);
    }
}());
hover for result

7

What is the output? Will it error and break? Is test defined?

(function () {
    if (false) {
        var test = 3;
    } else {
        console.log(test + 2);
    }
}());
hover for result

NaN

What is the output? Is one defined? Will it error? Or is it one of these digits: 3, 4, 5, or 6?

(function () {
    test = 5;

    if (false) {
        var test = 3;
    } else {
        console.log(one(test));
    }

    function one(value) {
        return value + 1;
    }
}());
hover for result

6

What is the output? Is one defined?

(function () {
    test = 5;

    if (false) {
        var test = 3;
    } else {
        console.log(one(test));
    }

    var one = function (value) {
        return value + 1;
    };
}());
hover for result

TypeError: undefined is not a function

Is the function one hoisted to the top of the highest scope? Is one a function or an integer? What is one where? ;)

(function () {
    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        }(test));

    console.log(one);
}());
hover for result

1

Is one hoisted to the top of the highest scope?

(function () {
    console.log(one(3));

    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));
}());
hover for result

TypeError: undefined is not a function

What are the values of one? What is the output? Does recursion still apply? Which one declarations have precedence where?

(function () {
    console.log(one(3));

    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    function one(value) {
        return value;
    }
}());
hover for result

3,1

Is one still hoisted to the top even though it’s immediately executed? Does it behave the same as before?

(function () {
    console.log(one(3));

    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    function one(value) {
        return value;
    }(4);
}());
hover for result

3,1

Is one hoisted to the top now that it’s enclosed by parenthesis?

(function () {
    console.log(one(3));

    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    (function one(value) {
        return value;
    }(4));
}());
hover for result

TypeError: undefined is not a function

Is one hoisted to the top even though it’s immediately executed and assigned with a name?

(function () {
    console.log(one(3));

    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    var identity = function one(value) {
        return value;
    }(4);
}());
hover for result

TypeError: undefined is not a function

What’s the output?

(function () {
    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    var identity = function one(value) {
        return value;
    }(4);
    console.log(identity);
}());
hover for result

1,4

What’s the output?

(function () {
    var test = 5,
        one = (function one(value) {
            if (value > 2) {
                return one(value - 1);
            }
            return value - 1;
        });

    console.log(one(test));

    var identity = function one(value) {
        return value;
    }(4);
    console.log(identity(3));
}());
hover for result

TypeError: number is not a function

Lessons Learned

  • When var is not used, variables are made global
  • Variable names take precedence over function names (in the case of duplicates)
  • Variable declarations (e.g. var myObj) are hoisted to the top of function scope; however, assignment is NOT hoisted
  • Function declarations (e.g. function myFunc() { }) are hoisted to the top of function scope
  • Function expressions (e.g. var myFunc = function someFunc() { }) are NOT hoisted to the top of function scope
    • They are treated like variable declarations–the variable definition is hoisted, but the assignment is not hoisted
    • someFunc cannot be called outside of its assignment; someFunc is undefined (ReferenceError); must use myFunc
  • Immediately executing function declarations has no effect on hoisting–the function will still be hoisted to the top of function scope

More JavaScript

Coercion in JavaScript

Bang and Double Bang

To me, coercion in JavaScript is another topic I’ve found interesting to explore. unexpected results. When using the bang (!)–also known as logical not–or double bang (!!) before a value, JavaScript coerces the value to a boolean and yields the opposite value:

!false                      //true
!0;                         //true
!!0;                        //false
typeof !!0                  //boolean
typeof !!0 == "boolean"     //true

Now to take it a step further by comparing the coerced values with the double equals operator:

!!0 == false    //true
!!'' == ''      //true
!!0 == 0        //true
!!1 == 1        //true
!!'0' == '0'    //false

How about that last line?

JavaScript coerces the first operand and then evaluates the entire expression. The first operand coerces to true leaving true == '0' as the expression to be evaluated. Under this scenario, the types of each value are different and one of them is a boolean, so JavaScript tries to convert each to a number. This results in 1 === NaN, which is obviously false. For another look at how the double equals comparison operator works in JavaScript, read this blog post.

If Blocks

In the context of if blocks, coercion applies very similarly.

if ('hi') { 
	console.log('hi');  //hi
}
if (1) { 
	console.log(1);     //1
}
if ('') { 
	console.log('');    // statement never reached
}

JavaScript coerces the string 'hi' the same way it would if we put !!'hi'. We could pass in a variable and it would be coerced the same way as well.

var val = 'hi';
if (val) { 
	console.log(val);	//hi
}

Therefore…

if ('hi') { 
	console.log('hi' == false);	//false
	console.log('hi' == true);	//false
}

Wait a second. Shouldn’t console.log('hi' == true); produce true? This is mostly a mind trick. We see 'hi' is truthy in the if statement, but when it’s compared to true with the double equals operator, it behaves similar to the example above–JS tries to convert 'hi' to a number first which results in NaN and then the whole expression is evaluated and it produces false. If this doesn’t make sense, you really need to read up on the double equals operator to understand how it works.

Why !!

So why would you ever use !!? It’s mostly a concise way of converting a value to a boolean or making sure it is a boolean. Alternatively, you could use the Boolean function, but it’s important to understand this has some tricks too. Before revealing the result below or reading any further, take a guess at what each line yields:

!!Boolean(false)
!!new Boolean(false)
hover for result

false,true

The new prefix constructs a boolean object. An object coerced yields true.

!new Boolean(false) !== !!!{}
hover for result

false

More JavaScript

Logical Operators in JavaScript

Logical operators in JavaScript can be a clean and simple way to return or set values without introducing extra if statements.

console.log(true || false);                //true
console.log(true && false);                //false
console.log(true && 0 && false);           //0
console.log(true && 'string' && 1);        //1
console.log(false || 'string' || false);   //string
console.log(false || 0 || 'string');       //string
console.log(false || 1 && 'string');       //string
console.log(false || 1 && 0 && 'string');  //0
console.log(false || 1 && 0 || 'string');  //string

This comes in hand when you want to make sure a variable has a value. This can be a concise way of preventing errors.

var persons = [
    {id: 1, name: 'joe', age: 22},
    {id: 2, name: 'harry', age: 59},
    {id: 3, name: 'will', age: 30}
];
var index = 19;
var person = persons[index];
console.log(person.name); //error

Well that’s no good. Let’s say index is derived from user input and you don’t want it to error if the index is out of bounds:

console.log(person && person.name); //undefined

Much better. You could also test index. If it’s not a valid value, then set it to a default.

index = index < persons.length || 0; //0
var person = persons[index];
console.log(person && person.name); //joe

This is a very contrived example, but hopefully you get the idea.

Arguably, adding logical operators on the same line doesn’t always make for the most readable code, but with practice I’ve found it to be quite readable and concise, as long as you don’t pack too many operations on one line.

That said, it’s not always easily tested. Each line of code performs multiple functions, so you can’t put break points right where you want them.

More JavaScript

Double Equals Comparison Operator in JavaScript

I’ve been doing a lot of development in JavaScript lately. I’ve found that evaluating values using the double equals comparison operator in JavaScript can produce some intriguing results.

First, I want to clarify the difference between double equals (==) and triple equals (===) in JavaScript. Double equals evaluates equality WITH type coercion while triple equals evaluates equality WITHOUT type coercion. Thus:

0 == false     //true
0 === false    //false

Double Equals (==)

Now for some more examples. For starters, when comparing '0' and '' to false, both evaluate to true:

'0' == false    //true
'' == false     //true

However, when we compare them against each other:

'0' == ''   //false

Interesting. Why is that? This is how the double equals works:

Equal (==)

If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory (Comparison Operators, Mozilla Developer Network).

So, with the example at hand, JS evaluates the operand type first. Since neither operand is a number or boolean and at least one of the operands is a string, they are evaluated as strings. (In this case, just so happens both operands are strings.) Next JS evaluates the values, which are different. Despite the “falsey” nature of both zero and the empty string, as string types they are altogether different values and therefore not equal.

Let’s take a look at a couple other intriguing examples.

'' == '0'           // false
0 == ''             // true
0 == '0'            // true
false == 'false'    // false
false == '0'        // true
false == undefined  // false
false == null       // false
null == undefined   // true
' \t\r\n ' == 0     // true

To explain some of these examples that were perplexing to me the first time I examined them…

When comparing false == 'false', JS tries to convert both to numbers. The result is 0 === NaN, which is of course false. This also explains why false == '0' is true–because it boils down to 0 === 0.

It appears that when ' \t\r\n ' is converted to a number, JS converts it to 0. At any rate isNaN(' \t\r\n ') results in false, which tells me that when converted to a number, ' \t\r\n ' does NOT result in NaN. Therefore ' \t\r\n ' must boil down to 0 since ' \t\r\n ' == 0 is true.

For further reading and in depth analysis with helpful tables, I highly suggest reading Truth, Equality and JavaScript by Angus Croll.

Final Thoughts

Some developers avoid using == in their code because they don’t understand it and it’s confusing. I think it’s important to understand how == works since this will lead to language mastery. Furthermore, if you don’t use ==, your colleagues or 3rd party libraries will, and if you don’t understand it, then you are disempowered. After you understand ==, I see no problem with not using it. But simply avoiding it because it’s confusing and you don’t understand it seems unwise.

If you’re interested in the actual specification: Abstract Equality Comparison Algorithm

If performance is of concern when using == vs ===, these may be worth perusing:

More JavaScript

Block Scope and Function Scope in JavaScript

Block Scope

JavaScript does NOT have block scope (think if blocks and the like). Variables used before assignment will be undefined and variables used after assignment will yield the expected value.

function a() {
    var hi = 'hi';
    console.log(hi);  //hi
    console.log(bye); //undefined

    if (true) {
        var bye = 'bye';
        console.log(hi);  //hi
        console.log(bye); //bye
    }
    console.log(hi);  //hi
    console.log(bye); //bye
}

Why? Because JavaScript hoists all variable declarations to the top of the function upon rendering the code. So effectively it is interpreted like this:

function a() {
    var hi, bye;    
    hi = 'hi';
    console.log(hi);  //hi
    console.log(bye); //undefined

    if (true) {
        bye = 'bye';
        console.log(hi);  //hi
        console.log(bye); //bye
    }
    console.log(hi);  //hi
    console.log(bye); //bye
}

The variable declarations hi and bye are hoisted to the top of the function and assigned as you would expect. As a result, bye is undefined when it is first referenced outside the if block and we don’t get an error. However, the second time it is referenced outside the if block, it has the appropriately assigned value, even though it is out of block scope.

Function Scope

JavaScript DOES have function scope. Variables defined in inner function scope and used in outer function scope will result in an error because the variable has not been defined in scope.

function a() {
    var hi = 'hi';
    console.log(hi);  //hi
    console.log(bye); //error

    function b() {
        var bye = 'bye';
        console.log(hi);
        console.log(bye);
    }
    b();
    console.log(hi);
    console.log(bye);
}

Variables used in outer function scope even after inner function scope assignment will result in error as well; however, if a variable has been defined in outer function scope, JavaScript will reach those variables and refer to their values within inner function scope.

function a() {
    var hi = 'hi';
    function b() {
        var bye = 'bye';
        console.log(hi);  //hi
        console.log(bye); //bye
    }
    b();
    console.log(hi);  //hi
    console.log(bye); //error
}

What about functions defined in inner scope and referenced in outer scope?

function a() {
    var hi = 'hi';
    function b() {
        var bye = 'bye';
        console.log(hi);  //hi
        console.log(bye); //bye
    }
    b();
}
b(); //error

The same holds true for them as well. Function scope is strict.

More JavaScript