Pitfalls of the newbie JavaScripter

In today’s tutorial, I’m going to educate you on the pitfalls of JavaScript, so we can be a better JavaScripter together. We’re going to talk about:

  1. Global variables
  2. Immediately self-invoking anonymous functions
  3. Function scope
  4. this keyword
  5. Hoisting
  6. Programming style
  7. Prototyping
  8. Chaining

In this article, I will assume you have a basic knowledge of programming and have fiddled with JavaScript before.

When we think of JavaScript, we mostly think of development for the web browser. There are other applications of JavaScript, but to keep it simple, we’ll stick to behavior that’s native to web browsers.

Global variables

When we talk about global variables, we talk about variables that get inserted into the root object of the current environment. In the browser, that is the window object. This means that whenever you try to access some global variable, you can do so through window.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
myVar = 'Hello there, dear visitor';
 
console.log(myVar); // 'Hello there, dear visitor'
 
var myFunction = function(){
    console.log(myVar);        // 'Hello there, dear visitor'
    console.log(window.myVar); // 'Hello there, dear visitor'
};
 
myFunction();
 
var mySecondFunction = function(){
    var myVar = 'This differs';
    console.log(myVar);        // 'This differs'
    console.log(window.myVar); // 'Helo there, dear visitor'
};
 
mySecondFunction();

Right at the start, we’ve tackled some behavior unique to window. Everything that can be accessed through window, can be accessed directly in every scope, unless it’s been redeclared, in wich case the locally declared variable will be used.

Lines 1,3,6,7 and 15 use a global reference.
Line 14 used a local reference, defined at line 13 in the local scope of mySecondFunction.

To make sure we don’t pollute the global scope of our application, we always precede our local variables with a var declaration.

var myThirdFunction = function(){
    var localVar = 'This one is local';
    someVar = 'Hello World!';
}
 
console.log(someVar); // 'Hello World!'
console.log(localVar); // undefined

The benefit is that these local variables don’t overwrite existing variables.

Let’s get a real world example.

File: calculator.js

kilo = 1000;
var Calculator = function(i){
    this.value = i || 0;
    this.k = function(v){ var v=v||this.value; return kilo*v; }; 
};

File: translate-metrics.js

ton = 'Ton';
kilo = 'Kilo';
milli = 'Milli';

Example: implementing calculator.js

c = new Calculator(12);
 
// Let's calculate what a thousandfold of these values looks like
m = c.k();   // 12000
n = c.k(13); // 13000
c.value = 14;
o = c.k();   // 14000

But when we combine it with translate-metrics.js, we set the global variable kilo to a string and thus our Calculator.k method will return NaN, which tells us that it tried to calculate something that was Not a Number.

Immediately self-invoking anonymous functions

So, how do we prevent JavaScript from leaking information between libraries? We do this using self-invoking functions or even anonymous self-invoking functions.

JavaScript has a great way of parsing itself, before handing over the result to the next function. This means we can do a lot of cool stuff like chaining and prototyping, but I’ll talk about those later on. What this also enables us to do is directly invoking a function after it’s been declared.

var myFunc = function(){
    console.log('I\'m running wild here!');
}(); // 'I\'m running wild here!'

As you can see, I just declared a function that outputs a line to the console and directly after declaration, I invoke it using (), rather than issuing myFunc(); separately.
The thing is, we could also do that with an anonymous function, like so:

function(){ console.log('Hello'); }(); // 'Hello'

Because JavaScript allows us to place ( ) around pretty much everything, we make use of that to create a function without giving it a name. Thus, the immediately self-invoking anonymous function.

(function(){ console.log('Hello'); })(); // 'Hello'

And finally, this enables us to declare variables that don’t pollute the global scope.

(function(){
    var myLocalVar = 'Hello';
    console.log(myLocalVar); // 'Hello'
})();
 
console.log(myLocalVar); // undefined

Yet inside the anonymous function, we can still make use of the global variables and even declare functions to the global scope. That’s what the window object is all about.

Function scope

Now comes the tricky part. If you’re used to a language like Java or PHP, you’re working on a block scope base. JavaScript, however, uses a function scope.

PHP: Block scope

<?php
$variable = 'Hello';
 
function myFunc(){
    echo $variable; // undefined
}
 
function myFunc2(){
    global $variable;
    echo $variable; // 'Hello'
}
 
myFunc();
myFunc2();
?>

JavaScript: Function scope

var variable = 'Hello';
var myFunc = function(){
    var internal = 'Hiya';
 
    console.log(variable); // 'Hello'
 
    var internalFunc = function(){
        var deepInternal = 'Howdy';
        console.log(deepInternal); // 'Howdy'
        console.log(internal);     // 'Hiya'
        console.log(variable);     // 'Hello'
    }();
 
    console.log(deepInternal); // undefined
}();

As you can see, all the children of the current scope can access what’s in the local scope and in the parent scope, up until the root scope. That, however, works in one direction, as the parent cannot access a variable inside the child scope, unless it gets specifically returned by return.

What you also need to know is that if you close a scope, all the variables that belong to that scope are no longer accessible.

(function(){
    var someVar = 12;
    window.myFunc = function(){
        console.log(someVar);
    };
    myFunc(); // 12
})();
 
myFunc(); // gives a reference error, stating that window.someVar was not declared

The reason why this happens is because someVar was accessible in the anonymous function and the first time we invoke the function, it was still within that scope. Now, when we invoked it later on, since it was declared to the window object, it no longer sees that variable in the current scope and thus references to something that no longer exists.

this keyword

The behavior above can be explained by the behavior of the this keyword. You could rewrite someVar as this.someVar. Now, what is this? this refers to the current scope of the function or object you’re working with. That is really useful when you don’t know the context in which your code will be applied. It is intensely used when one creates an Object in JavaScript.

var Meeting = function(host,guest){
    this.host = host || new Person();
    this.guest = guest || new Person();
    this.handShake = function(cb){
        console.log(this.host.shakeHand()+' I am the host of this meeting.');
        console.log(this.guest.shakeHand()+' I am the guest of this meeting.');
        if(typeof cb == 'function'){
            cb(); // Call this function whenever the handshake is done.
        }
    };
};
 
var Person = function(name,age){
    this.name = name || 'John Doe';
    this.age = age || 0;
    this.shakeHand = function(){
        return 'Hello, my name is '+this.name+' and I\'m '+this.age+' years old.';
    };
};
 
var bob = new Person('Bob',40);
var amy = new Person('Amy',38);
 
var meeting = new Meeting(bob,amy);
meeting.handShake();

This simply outputs:

Hello, my name is Bob and I'm 40 years old. I am the host of this meeting.
Hello, my name is Amy and I'm 38 years old. I am the guest of this meeting.

But what if we play around with this nifty callback function we implemented, so we can run things when the handshake was done?

First, let’s set up a couple of meetings.

meetings = [
    {
        h:{
            n:'Bob',
            a:40
        },
        g:{
            n:'Amy',
            a:38
        }
    },
    {
        h:{
            n:'Janet',
            a:42
        },
        g:{
            n:'Peter',
            a:26
        }
    },
    {
        h:{
            n:'Marlin',
            a:32
        },
        g:{
            n:'John',
            a:38
        }
    }
];
 
for(var i=0;i<meetings.length;i++){
    var m = meetings[i];
    var host = new Person(m.h.n,m.h.a);
    var guest = new Person(m.g.n,m.g.a);
    var meeting = new Meeting(host,guest);
    meeting.handShake();
}

Output:

Hello, my name is Bob and I'm 40 years old. I am the host of this meeting.
Hello, my name is Amy and I'm 38 years old. I am the guest of this meeting.
Hello, my name is Janet and I'm 42 years old. I am the host of this meeting.
Hello, my name is Peter and I'm 26 years old. I am the guest of this meeting.
Hello, my name is Marlin and I'm 32 years old. I am the host of this meeting.
Hello, my name is John and I'm 38 years old. I am the guest of this meeting.
(function(){
for(var i=0;i<meetings.length;i++){
    var m = meetings[i];
    var host = new Person(m.h.n,m.h.a);
    var guest = new Person(m.g.n,m.g.a);
    var meeting = new Meeting(host,guest);
    meeting.handShake(function(){
        console.log(this.i); // undefined
        this.handShake(); // repeats the handShake, without callback
    });
})();

So, that’s rather annoying. When you have a good look at it, you’ll notice that the callback function is actually declared in another scope then where it’s executed, but that’s something we can do by mistake really easily in this case. So, how do we fix this?

(function(){
for(var i=0;i<meetings.length;i++){
    var parent = this;
    var m = meetings[i];
    var host = new Person(m.h.n,m.h.a);
    var guest = new Person(m.g.n,m.g.a);
    var meeting = new Meeting(host,guest);
    meeting.handShake(function(){
        console.log(parent.i); // 0 || 1 || 2
    });
})();

This simply puts the this object into a variable and passes this variable on to the function in the callback. One of the implementations of myself that had this issue, just recently:

...
 
Storage.prototype.script = function(k,f){
    if(!this.scriptNodeExists(k)&&!this.injectScriptNode(k)&&Xhr!==undefined){
        var x = new Xhr,t=this;
        x.parentScope=this;
        x.callback = function(){
            t.setItemEncoded(k,x.response);
            t.injectScriptNode(k);
        };
        x.get(f);
    }
}
 
...

The problem was that setItemEncoded and injectScriptNode are methods I made for the Storage object and not for the Xhr object. I am, however, running a callback function that needs to execute functions of this very same object, whenever the Xhr object finishes getting the file from the server.

Thanks to great support from Pepkin88 in the comments, here’s a simple problem that displays the behavior of this. I made some minor improvements, but props to Pepkin88.

[jsfiddle url="http://jsfiddle.net/johmanx10/hmn76/12/" height="770px" include="js,result"]

Hoisting

You’ve probably read or heard about good programming habits concerning JavaScript. It was mentioned that it’s a good habit to declare variables at the top of a function, but why exactly? Well, that’s because JavaScript loves function and variable hoisting.

No, we’re not talking about some pirate that’s hoisting your goods. JavaScript has this behavior of declaring variables at the top of the scope. Now, what implications does this have?

var someVar = 'Hello';
 
(function(){
    console.log(someVar); // Hello
})();
 
(function(){
    var someVar = 'Hiya';
    console.log(someVar); // Hiya
})();
 
(function(){
    console.log(someVar); // undefined
    var someVar = 'Howdy';
})();

Huh? So, how does that work? Well, JavaScript has some behavior in the background that hoists var declarations to the top of the scope. That is why you can invoke functions you declare later on in the code, as long as you don’t run the function that invokes them before they are declared. This, however, on the background renders the following JavaScript for the last function:

(function(){
    var someVar;
    console.log(someVar); // undefined
    someVar = 'Howdy';
})();

And now you can clearly see that the value of someVar has been reset and not yet defined.

Programming style

It has been a holy war between programmers. Some people like their brackets left, others right. Some people like indentation with tabs, others with spaces. Some like 2 spaces, others like 8 spaces. I like programming with my brackets right and 4 spaces indentation. That has been really different in the past, when I was only focusing on PHP. I program with 2 monitors of 24″ side-by-side, so my indentation used to be really optimized for readability. It was:

function()
    {
        $var = 'hello';
        return $var;
    }

This got some critique really early on by fellow programmers, but I kept on using it like this, until the unexplainable bugs started happening. JavaScript has a .. ahum .. really neat engine that automatically fixes your broken code, where you forgot your semicolon. Really great for starting programmers. Not so great for professional development. So, what happens?

(function(){
    return
        {
            a: 12,
            b: 13
        };
})(); // undefined

How can this be undefined? It’s the only thing in the fracking function, right? Well, what happens is the engine puts a semicolon behind the return, which in turn returns not quite as much as we would like. The object that get’s declared afterwards will be skipped, because return breaks the function.

So, it’s good behavior to put your brackets on the right, so the engine won’t break your code for you.

Prototyping

Now here comes the power of JavaScript. Everything in this beautiful language is extendable. Even the objects and functions that come packed with your environment. So, what is prototyping?

Everything, except for values and expressions, in JavaScript has a prototype. And although a value has no prototype, the Object it originates from does. The prototype can redefine how an Object behaves and can add functionality to the Object. Even the prototype itself has a prototype, which has a prototype, and so on, until the root is reached.

var arr = [1,2,4,5,33]; // This originates from the object Array
Array.prototype.sum = function(){
    var sum = 0;
    for(var i=0;i<this.length;i++){
        sum += this[i];
    }
    return sum;
}
 
console.log(arr.sum()); // 45

Since arr originated from the object Array, we can add functionality to it through changing the prototype of Array. Now we have a function to calculate the total sum of the numbers inside the array. Prototypes can also invoke methods that were declared inside the prototype as such:

Array.prototype.avg = function(){
    return this.sum() / this.length;
};
console.log(arr.avg()); // 9

That’s great for calculating your average income and expenses.

Prototyping has effect on all the variables that originated from that object, even if they were declared before the prototype changed.

n = new Number(12);
console.log(n.valueOf()); // 12
 
// Only works with positive numbers. Just for demo purposes
Number.prototype.power = function(n){var n=n||2,r=this.valueOf();n--;for(var i=0;i<n;i++){r*=this.valueOf();};return r;};
n.power();  // 144
n.power(2); // 144
n.power(3); // 1728

And now we can do some basic math function without issuing the Math object.

Let’s note that simply prototyping may brick third party code, since it may have unexpected behavior. Libraries are almost always built with the underlying thought that the prototype of core functionality stays untouched. In that respect, you should always check if the object exists and if the method you try to prototype wasn’t already declared.

var Proto = function(){
    this.extendable = function(o,m){
        return (window[o]!==undefined&&window[o][m]===undefined&&window[o].prototype[m]===undefined);
    }
    this.exists = function(o,m){
        return (window[o]!==undefined&&(window[o][m]!==undefined||window[o].prototype[m]!==undefined));
    }
    this.extend = function(o,m,f,d){
        if(this.extendable(o,m)&&(d===undefined||this.exists(o,d))){
            window[o].prototype[m]=f;
        }
    }
    return this;
};
 
// If Array exists and has no method sum
Proto().extend('Array','sum',function(){
    var sum = 0;
    for(var i=0;i<this.length;i++){
        sum += this[i];
    }
    return sum;
});
 
// If Array exists, has no method avg and has method sum
Proto().extend('Array','avg',function(){
    return this.sum() / this.length;
},'sum');

At first we made an Object called Proto. This checks if the prototype is extendable and if so, extends upon the prototype. Later on, we create the method Array.prototype.sum which enables us to do the sum function on arrays. Finally we create the Array.prototype.avg method, which depends on Array.prototype.sum. If the dependency exists, it gets declared and because it does, we now also have the avg method to use on arrays.

We could improve this a lot. For instance, we could allow inter-Object dependencies and check multiple dependencies instead of one, but for the sake of the tutorial, I’m not going to build that extra functionality in here.

Chaining

The Proto object we just made was also an example of a short chain. What we did was execute a function, return this and move on with the result of that. The reason we can chain in JavaScript is because it executes and parses functions on the fly, so you can select the result directly in the same line of code. Two that are used a lot in general web development are:

document.getElementByTagName('script')[0];

and

var e = function(e){return document.getElementById(e);};

As you can see in the first example, we first call the document object, ask it to run the method getElementByTagName with the parameter script. This gives us an array of Nodes that fit the tagname of script. From that array, we take the first item by issuing [0] (zero indexing).

A library that makes really good use of this behavior is jQuery.

jQuery example:

$('ul').children('li').each(function(){
    $(this).hide().fadeIn('slow').addClass('fade-in');
});

And it’s near endless how far jQuery let’s you chain up functions. Now, how is this possible?

jQuery stores the selected item that was defined using $() inside the corresponding object. It then passes that item on to the method we called, children, which in turn returns that same item, or the result of that item. In any case, it returns a jQuery object. And that is the interesting part, since the return value can be called again using JavaScript, due to it’s behavior. So now when the method children finishes, it returns a jQuery object. That jQuery object has all the same methods the previous jQuery object had, so all methods are available yet again.

$('body')               //returns jQuery object
.find('#head')          //returns jQuery object
.addClass('js-enabled') // returns jQuery object
.html('Hello');         // returns jQuery object || String object

But we can do that too and on a really small scale as well.

Combining previous code:

[12,3,0].avg().power(3); // 125

First we have an array. That originates from Array. Array has the prototype method avg. That in turn returns a number, which originates from Number. Number has the prototype method power and with the parameter of 3, it does Number^3.

The sum of the array is 15. The length of the array is 3. The average is 5. 5^3 = 5 * 5 * 5 = 125

Conclusion

JavaScript is a really useful and powerful language, that has been misunderstood by many, due to it’s alternative behavior that leads to a lot of bugs and frustrations. Nonetheless, JavaScript is a real mature language that helps us developers out on many occasions. With the ever growing number of stable and helpful libraries like jQuery, MooTools and Dojo, we see a real growth in support and enthusiasm for the language.

JavaScript has a somewhat high learning curve, even for seasoned programmers, but can be a really easy-going language once one is familiar with the quirks. I hope this article helps overcome those quirks and lowers the border for programmers that are new to JavaScript or just haven’t used the language to it’s full potential.

16 thoughts on “Pitfalls of the newbie JavaScripter

  1. Hi, I just want to point to an error in one of your examples.

    (function(){
    var someVar = 12;
    window.myFunc = function(){
    console.log(someVar);
    }(); // 12
    })();
    myFunc();

    You don’t get a ReferenceError but a TypeError stating that myFunc is not a function. That is because you assign undefined to window.myFunc. The expression is interpreted like this:

    window.myFunc = function () { console.log(someVar); return undefined; }();

    As you can see the function returns undefined and since you auto-execute the function before the assignment, that is what gets assigned to window.myFunc.

    If you didn’t auto-execute the function, the function itself is would be assigned to window.myFunc and when you called the function (at the bottom of your example), you wouldn’t get a ReferenceError because the contents of the scope in which someVar is declared were not garbage-collected as you create a closure that keeps a reference to the variable.

    Cheers ;-)

      • It’s still wrong though. You don’t get an error. The someVar variable is not disposed. The code is completely OK.

      • The reason why someVar isn’t disposed is because a JavaScript function is a closure. That means every variable which is visible for the function (even if you’re not using all of them) remains as long as that function could be used (the reference to that function isn’t lost).
        There is no need for another example of the function scope.

      • Strictly speaking I made mistake. A JavaScript function isn’t a closure, but creates one. That function WITH every variable accessed from its scope is a closure.
        (I hope I haven’t mistaken on this one.)

  2. Your section on hoisting (and watefalling down from that) contain a bunch of these:

    (functon() { … });

    When I believe you actually want…

    (function() { …})();

    The code samples you’re showing off there would never actually execute. ;)

  3. In section about self-invoking anonymous functions you write:
    “Because JavaScript allows us to place ( ) around pretty much everything, we make use of that for better readability.”
    Actually it is not for better readability. Statement without the parenthesis is function definition, but with error, because function definition requires giving name. But with the parenthesis the code is parsed as function expression, which allows not giving a name for a function.

      • Also the self-invoking function doesn’t have to be anonymous. For example:
        var result = (function factorial(n) {
        return n < 2 ? 1 : n * factorial(n – 1);
        })(5);
        We created self-invoking recursive non-anonymous function. Here I could omit the parenthesis and the code would still work:
        var result = function factorial(n) {
        return n < 2 ? 1 : n * factorial(n – 1);
        }(5);
        That's because function statement in this syntax can only be function expression. And being function expression is essential when we are trying to create self-invoking functions. Although, as you've written first, putting this statement in parenthesis increases readability.
        However parenthesis are important and necessary when the function statement is first thing on a line, because only then it could be misinterpreted as function definition.

        I'm sure you are aware of those things, I just wanted to clarify some issues.
        Anyway, great article :)

      • And by “self-invoking function” I meant “immediately self-invoking function” as opposed to simple recursion. Sorry for inconsistence.

  4. I think it is a good idea to show a certain problem with “this” keyword, namely: http://jsfiddle.net/pepkin88/G6Ld2/1/

    When you invoke a private function from your object’s method you should remember that “this” keyword refers to current object only in that function’s scope [1][2] (and not even in the nested function’s scope [3]). To repair this use call method of function [4][5] or use “this” reference saved in other variable [6][7].

    Cheers.

    • You’re a great help and I’m going to implement your example in the article pretty soon-ish. I really want this to be an excellent resource on the net, so we can all reference it when we need it. That’s why I really appreciate all the input, since I’m no expert at JavaScript at all.

      If you have suggestions for the article like you did before, don’t be shy to share it, ’cause I really want us developers to make a better web together. Isn’t that why we put the effort in writing this tutorials?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">