Blog

How Good C# Habits can Encourage Bad JavaScript Habits: Part 3 – Function Scope, Hoisting, & Closures

This is the third post in a multi-part series covering common mistakes C# developers tend to make when they first start writing JavaScript.

The first post covered the following topics:

  • 1. Having Variables & Functions in Global Scope
  • 2. Not Declaring Arrays & Objects Correctly

The second post covered the following topics:

  • 3. Not Understanding False-y Values
  • 4. Not Testing & Setting Default Values Correctly
  • 5. Using the Wrong Comparison Operators
  • 6. Not Using the for…in Statement Correctly

Introduction

This post continues to focus on areas where C# developers tend to make bad JavaScript decisions based on their previous training. The languages are similar enough syntactically that C# developers tend to not invest the time to learn JavaScript’s differences.

The following post points out several misunderstandings that can get you into some confusing situations.

More Bad Practices

7. Misunderstanding Scope in JavaScript

Understanding the different between Block Scope (what C# uses) and Function Scope (what JavaScript uses) is one of the most important things you should know when moving from C# to JavaScript. If you don’t understand this concept then things can get confusing real quick.

In C#, if you declare a variable inside of a set of brackets then the lifetime of the variable only lives inside that scope. However, in JavaScript, the variables you declare inside a function are available to any other code within that function scope.

Let’s look at the following code and see what concepts we can learn.

// Code written thinking that JavaScript has block scope
function eat() {
    var food = "bacon",
        isHungry = true;

<pre><code>if ( isHungry ) {
    //A C# developer might think that timeToWait is
    //only accessible from within this if statement,
    //but that is not the case
    var timeToWait = 10;

    console.log( &amp;quot;Waiting &amp;quot; + timeToWait + &amp;quot; minutes&amp;quot; );

    chew();
}

function chew() {
    var bodyPart = &amp;quot;mouth&amp;quot;;

    //The chew function also has access to the
    //timeToWait variable because it is part of the
    //eat function's scope
    console.log( &amp;quot;After waiting &amp;quot; + timeToWait +
        &amp;quot; minutes, &amp;quot; + &amp;quot;I am eating &amp;quot; + food +
        &amp;quot; with my &amp;quot; + bodyPart );
}
</code></pre>

}

eat();
//Waiting 10 minutes
//After waiting 10 minutes, I am eating bacon with my mouth

You can execute and modify the above code from

jsFiddle.

A C# developer might look at the above code and think that the timeToWait variable is only accessible by the if statement, but that isn’t true. The timeToWait variable is accessible anywhere within the eat function. So, that means the chew method can use the timeToWait variable as well.

If the above code snippet is confusing to you, it is probably because of something called variable and function hoisting. We will discuss these concepts in the next section, which should help clear up some of the confusion that you may have.

<

pre>
Instead of declaring your variables throughout the eat function, they should have all been declared at the top. By doing so, it would be more obvious that the scope is on the function and not the block level as a C# developer might expect. I have rearranged the variable declaration to make more sense below.

// Code written understanding JavaScript has function scope
function eat() {
    //Declare all your variables at the top so that it is
    //obvious you are using function scope and not block
    //scope
    var food = &quot;bacon&quot;,
        isHungry = true,
        timeToWait, bodyPart;

<pre><code>if ( isHungry ) {
    timeToWait = 10;

    console.log( &amp;quot;Waiting &amp;quot; + timeToWait + &amp;quot; minutes&amp;quot; );

    chew();
}

function chew() {
    bodyPart = &amp;quot;mouth&amp;quot;;

    console.log( &amp;quot;After waiting &amp;quot; + timeToWait +
        &amp;quot; minutes. &amp;quot; + &amp;quot;I am eating &amp;quot; + food +
        &amp;quot; with my &amp;quot; + bodyPart );
}
</code></pre>

}

eat();
//Waiting 10 minutes
//After waiting 10 minutes, I am eating bacon with my mouth

You can execute and modify the above code from

jsFiddle.

Best Practice

It is considered best practice to declare all of your variables at the top of your function. By declaring your variables at the top of your function, you are sending a message to yourself and anyone else that those variables are available to anything inside of the function.

It turns out there is an even more compelling reason to declare your variables at the top of your function.

8. Not Knowing Variable and Function Hoisting

As we examined in the above section, JavaScript uses Function Scope instead of Block Scope. How exactly does that work? Behind the scenes JavaScript does something called variable and function hoisting.

Variable Hoisting

In JavaScript all the variables inside of a function share the same scope. Inside of a function, JavaScript first looks for all the variable declarations, hoists their declarations to the top of the function, and then initializes them to undefined. Their assignments still remain on the same line where you originally declared them. This is known as 'variable hoisting'.

For example let's say that we wrote the following piece of JavaScript code

//Code You Might Write
function sayHello( firstName, middleName, lastName ) {
    var fullName = firstName + &quot; &quot; + middleName + &quot; &quot; +
        lastName;

<pre><code>if ( fullName === &amp;quot;Carlos Rey Norris&amp;quot; ) {
    var nickName = &amp;quot;Chuck&amp;quot;;

    console.log( &amp;quot;Hello &amp;quot; + nickName + &amp;quot; &amp;quot; +
        fullName.split(&amp;quot; &amp;quot;)[2] );
}
</code></pre>

}

sayHello( &quot;Carlos&quot;, &quot;Rey&quot;, &quot;Norris&quot; ); //Hello Chuck Norris

You can execute and modify the above code from

jsFiddle.

Behind the scenes JavaScript takes the fullName and nickName variables and declares them all at the top of the function. Their assignments remain in the same place, but their declaration location changed.

//How JavaScript Interprets It
function sayHello( firstName, middleName, lastName ) {
    //Hoists all the variable declarations to the top
    //of the function and sets to undefined
    var fullName = undefined,
        nickName = undefined;

<pre><code>//fullName assignment remains in original position
fullName = firstName + &amp;quot; &amp;quot; + middleName + &amp;quot; &amp;quot; + lastName;

if ( fullName === &amp;quot;Carlos Rey Norris&amp;quot; ) {
    //nickName assigned remains in original position
    nickName = &amp;quot;Chuck&amp;quot;;

    console.log( &amp;quot;Hello &amp;quot; + nickName + &amp;quot; &amp;quot; +
        fullName.split(&amp;quot; &amp;quot;)[2] );
}
</code></pre>

}

sayHello( &quot;Carlos&quot;, &quot;Rey&quot;, &quot;Norris&quot; ); //Hello Chuck Norris

You can execute and modify the above code from

jsFiddle.

Where Things Can Get Confusing: Part 1

Not knowing this can lead you into some pretty confusing situations. For example, take a look at the following example.

//Where You Can Get Into Trouble
for ( var i = 0; i < 10; ++i ) {
    for ( var i = 0; i < 5; ++i ) {
        console.log( "Hello" );
    }
}

Do you see what is wrong in the above code? The intent of the developer was to print out "Hello" 50 times, but the result is an infinite loop that prints out "Hello" continuously! A C# developer might think that each i variable is in it's own scope, but not in JavaScript. JavaScript hoisted the i variable to the top of the function and both loops are updating the same variable. The effect is that the inner loop is never letting the outter loop's i variable reach 10, which is why the code never exits the loop.

Where Things Can Get Confusing: Part 2

Here is another example of where you might get confused about scope. The following code declares someVariable outside of the function and then the someVariable variable is written to the console immediately inside the function. At first glance, that seems like it should work, but in the following example it does not!

//Where You Can Get Into Trouble

console.log( someVariable ); //undefined
var someVariable = 42; //Global variable
console.log( someVariable ); // 42

function doSomething() {
    console.log( someVariable ); // undefined
    //Why is someVariable undefined?
    //Developer expected to see 42 from global variable

<pre><code>someVariable = 1
console.log( someVariable ); // 1

console.log( window.someVariable ); // 42
//Why is window.someVariable 42?
//Developer thought he just set global variable to 1

if ( false ) {
    var someVariable = 0;
}
</code></pre>

}

doSomething();

console.log( someVariable ); // 42
//Why is someVariable is 42?
//Developer expected to see 1 from global variable

You can execute and modify the above code from

jsFiddle.

Let's rewrite the same code above, but this time as JavaScript would interpret it with variable hoisting.

//How JavaScript Interprets It

var someVariable = undefined;
console.log( someVariable ); //undefined
someVariable = 42; //Global variable
console.log( someVariable ); // 42

function doSomething() {
    //Because of variable hoisting var is
    //moved to the top of the function and set to undefined
    var someVariable = undefined;
    console.log( someVariable ); // undefined

<pre><code>someVariable = 1
console.log( someVariable ); // 1
//This above line of code didn't set the global
//instance, but the local one that was hoisted

console.log( window.someVariable ); // 42

if ( false ) {
    someVariable = 0;
}
</code></pre>

}

doSomething();

console.log( someVariable ); // 42
//Because of variable hoisting in
//doSomething the code inside never updated
//the global variable

You can execute and modify the above code from

jsFiddle.

When you understand how hoisting works it is easier to understand why the someVariable variable was undefined immediately inside the function. Since there was a var someVariable = 0; inside the if statement, that variable got hoisted to the top of the function. So, instead of "someVariable" referencing the global instance, it is referencing the local someVariable variable declared in the function scope.

As you can tell, if you don't have a good understanding on how function scope works, then you can get into some trouble real fast.

And Then There Was Function Hoisting

Now that you have a good grasp on variable hoisting, let's change our focus somewhat to function statements and function expressions. The hoisting rules for functions aren't exactly the same as they are for variables. First, we need to understand the difference between a function statement and a function expression. The easiest way to tell them apart is, if it starts with the function keyword, then it is a function statement. See the following examples comparing the two function declarations.

//Example with various function declarations

try {
    sayHello(); //Error because not defined
} catch (e) {
    //Property 'sayHello' of object [object DOMWindow]
    //is not a function
    console.log(e.message);
}
sayGoodbye(); //Goodbye

//Function Expression
var sayHello = function() {
    console.log("Hello");
};

sayHello(); //Hello
sayGoodbye(); //Goodbye

//Function Statement
function sayGoodbye() {
    console.log("Goodbye");
}

sayHello(); //Hello
sayGoodbye(); //Goodbye

You can execute and modify the above code from

jsFiddle.

The above function statement is transformed behind the scenes into a function expression and then both the variable and the assignment are hoisted to the top of the function scope.

For example, let me rewrite the above code snippet as JavaScript would interpret it.

//How JavaScript Interprets It

var sayHello = undefined,
    sayGoodbye = undefined;

//Function Statement was converted to a
//function expression and both the variable
//and assignment were hoisted to the top of
//the function
sayGoodbye = function() {
    console.log("Goodbye");
};

try {
    sayHello(); //error
} catch(e) {
    //Property 'sayHello' of object [object DOMWindow]
    //is not a function
    console.log(e.message);
}
sayGoodbye(); //Goodbye

//The declaration of the Function Expression was
//hoisted to the top of the function, but the
//assignment stayed in the original location
sayHello = function() {
    console.log("Hello");
};

sayHello(); //Hello
sayGoodbye(); //Goodbye

//sayGoodbye Function statement was here, but got
//completely hoisted to the top of the function

sayHello(); //Hello
sayGoodbye(); //Goodbye

You can execute and modify the above code from

jsFiddle.

As you can see from the above example, function expressions follow the same rules as variable hoisting, but function statements vary slightly. A function statement is first converted to a function expression and instead of just hoisting the declaration, it hoists both the declaration and the assignment of the function as well.

Best Practice

Since JavaScript uses Function Scope and hoists it's variable declarations, it is considered best practice to declare all of your variables at the top of your function.

9. Not Using Closures Correctly Or At All

Using a closure is a way to keep variables alive after a function has returned. The Mozilla Developer Network has a great page explaining closures. In it they provide a core definition:

"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."

A closure can be very helpful when needing to enclose certain variables to a particular scope or when we need to maintain state inside an object. We will examine a common code scenario and examine what is going on and how we might be able to fix it using a closure.

Looping Without A Closure

The intent of the following code snippet is to add an event handler to 10 different DOM elements and each one should alert it's ID attribute (e.g. "You've clicked 3"). You should know that if this was your actual intent, then there is a much easier way to do this, but for academic reasons let's stick with this implementation.

//broken
var unorderedList = $( "ul" );
for (var i = 0; i < 10; i++) {
    $("<li />", {
        id: i,
        text: "Link " + i,
        click: function() {
            console.log("You've clicked " + i);
        }
    }).appendTo( unorderedList );
}

You can execute and modify the above code from

jsFiddle.

The output of the above code may not be what you first expect. The result of every click handler will be "You've clicked 9" because the value of i at the point the event handler was fired is "9". What the developer really wanted is for the value of i to be displayed at the point in time the event handler was defined.

Looping With A Closure: Part 1

In order to fix the above bug we can introduce a closure.

//working
var unorderedList = $( "ul" ), i;

for (i = 0; i < 10; i++) {
    $("<li />", {
        id: i,
        text: "Link " + i,
        click: function(index) {
            return function() {
                console.log("You've clicked " + index);
            }
        }(i)
    }).appendTo( unorderedList );
}

You can execute and modify the above code from

jsFiddle.

One way to fix the above code is to utilize a self-executing anonymous function. That is a fancy term that means we are going to create a nameless function and then immediately call it. The value of this technique is that the scope of the variable stays within the function. So, first we will surround the event handler content in a function and then immediately call the function and pass in the value of i. By doing that, when the event handler is triggered it will contain the value of i that existed when the event handler was defined.

Looping With A Closure: Part 2

If the above syntax is new to you, then you might consider the following code snippet, which is essentially the same thing, but split out a little more. Instead of using an anonymous function, we are defining a named function and passing the value of i into it so the scope will remain in the function.

var unorderedList = $( "ul" ), i;

for (i = 0; i < 10; i++) {
    $("<li />", {
        id: i,
        text: "Link " + i,
        click: clickEventHandler(i)
    }).appendTo( unorderedList );
}

function clickEventHandler( index ) {
    return function() {
        console.log("You've clicked " + index);
    }
}

You can execute and modify the above code from jsFiddle.

Best Practice

As seen in the above examples, a closure can be very helpful when trying to persist certain variable states. There are actually several other really good uses for closures as well. A pattern that I use frequently is called the Revealing Module Pattern, which uses the concept of closures to simulate private methods and properties as you might expect from C#.

For more examples of when to use closures appropriately in your code there is a great post by Juriy Zaytsev on Script Junkie entitled Use Cases for JavaScript Closures

So What Now?

Tools To Help You

Many of the above issues we've addressed can be found during development by running your code through JSLint, which is a JavaScript code analyzer that Douglas Crockford developed. It takes many of the concepts from his experience and boils them down into a set of rules you can execute against your code.

You might also consider running your code through another tools called DoctorJS. This tool builds on the concepts taught by Douglas Crockford and extends them somewhat with their own best practices.

A combination of these two tools should help pinpoint some obvious practices that you should change in your code. Passing these tools does not mean you have good code, but it can help you identify areas that need some attention.

Sources for Additional Learning

As you've probably noticed I've mentioned Douglas Crockford a lot in this article. A lot of his work identifies areas where classical languages such as C# vary from JavaScript. He has a great book entitled JavaScript: The Good Parts that I highly suggest you reading. You can also check out his phenomenal Crockford on JavaScript video series on Yahoo! that covers much of the content of the previously mentioned book.

In addition, the JavaScript articles on the Microsoft Script Junkie website are top notch. I highly recommend checking them out. The authors on the site are top notch experts from the field. Here is a small taste of some of the great article you can find:

There is also a great blog post series by Julian Bucknall entitled JavaScript for C# Programmers. The posts were from some time ago, but their content is still timely and very much top notch.

Conclusion

The intent of these articles was to shed some light on practices that a C# already does that might become an immediate issue in JavaScript development.

In addition to the bad practices that I've mentioned in this series, there are many more things that a C# developer should know. JavaScript is a very powerful language and has unfortunately received a bad wrap primarily because of the painful nature of the DOM.

JavaScript is similar enough to C# that you feel comfortable, but different enough that is worth diving into it deeper. You can actually do some pretty cool things that you can't do in C#. I hope you find these tips helpful.

Tweet about this on TwitterShare on FacebookShare on RedditShare on Google+Share on LinkedIn

  • http://twitter.com/zachariahCurtis Zach Curtis

    Nice work. That loop syntax is new to me and looks like the self-executing anonymous function will be super helpful. Thanks!

  • http://twitter.com/vitor_canova Vitor Canova

    Wow, self-executing anonymous function is very complicate to undestand.

  • http://twitter.com/vitor_canova Vitor Canova

    How can I use a window.setInterval in the body of my public method and can access the instance? Example: I need to execute a pooling in my method but I want to access some public and private methods:

    (function Classe(){

    var instance = {};

    var myPrivate = 0;

    instance.Do = function(){

    console.log(“Did ” + instance.
    myPrivate);

    }

    instance.Loop = function(){

    window.setInterval(function(){

    if(instance._myPrivate == 1000){

    console.log(“So mutch work.”);

    }

    instance.Do();

    },1000);

    }

    return instance;

    })();

  • http://calvinf.com/ Calvin Freitas

    Another tool worth looking at is Google Closure Linter: http://code.google.com/p/closure-linter/

    Similar to JSLint, it's goal is to encourage good JavaScript coding practices — specifically, it uses the guidelines set by the Google JavaScript Style Guide.

  • http://twitter.com/rick_roth Rick Roth

    These are all great posts! Keep up the good work. It's good to have a resource like this to point developers to who are new to JavaScript coming from a .NET background.

    Another topic worth addressing along these lines is how C# developers have a tendency to only think along the lines of object-oriented programming when dealing with JavaScript, and don't embrace the dynamic aspects of the language. (And I'm guilty of that as well.)

    For example, we tend to want to organize our code for reuse by trying to simulate classes and interfaces and then following strict conventions to avoid breaking our OOP facade. We might try to code in a way that simulates the C# experience by following an object inheritence chain where our faux classes can only derive from one base class. By doing so we lose site of the flexibility that JavaScript gives us and forget we can dynamically add properties and methods to any object instance whenever we want, and can even combine many objects together by using mix-ins.

    It would be interesting to discuss effective ways to modularize code for reuse and contrast the differences in polymorphism and inheritence between JavaScript and C#. This would be very educational for C# programmers who find themselves writing more and more JavaScript these days (in our increasingly HTML 5 world) and would ultimately improve their understanding of and competency with both languages.

  • http://twitter.com/mvirkkunen Matti Virkkunen

    Just as a btw, the nested for loop example would not even compile as C#, as the compiler prevents confusing redeclaration of local variables:

    “A local variable named 'i' cannot be declared in this scope because it would give a different meaning to 'i', which is already used in a 'parent or current' scope to denote something else”

  • Pingback: Good JavaScript Habits For C# Developers by Elijah Manor | appendTo - The Company Dedicated to jQuery

  • Pingback: Good C# Habits, Bad JavaScript Habits | ChurchCode

  • http://checktrafficwebsite.com Hufaxian

    cool ,Great work`
    thanks for sharing