Mastering the Arcane Art of JavaScript-mancy for C# Developers - Chapter 1: The Many a One JavaScript Quirks

| Comments

The Mastering the Arcane Art of JavaScript-mancy series are my humble attempt at bringing my love for JavaScript to all other C# developers that haven’t yet discovered how awesome this language and its whole ecosystem are. These articles are excerpts of the super duper awesome JavaScript-Mancy book a compendium of all things JavaScript for C# developers.

For many years has JavaScript been frown upon and look down on by many developers due to its quirky nature, obscure behaviors and many a one WTFs that populate its hairy APIs and operations.

Frown upon no more! For with modern design patterns, libraries, tools and the long awaited JavaScript 6 Harmony (ES6, ES2015) writing JavaScript is now a pleasure.

Join me at the school of JavaScript-mancy as we travel along the modern landscape of writing JavaScript in 2015 and beyond, as we discover the organic evolution of this beautiful language and its thriving ecosystem, and delve in the latest features/spells/incantations of the JavaScript Arcana.

You my friend, cannot ignore JavaScript no longer, JavaScript is the most deployed language on earth, a beautiful and expressive language that supports many paradigms and which has a thriving community that continuously expands and improves its ecosystem with patterns, libraries, frameworks and tools. You don’t want to miss this train.

But JavaScript, though forgiving and specially conceived to be easy to learn, can be either daunting for us that have a strongly-typed mindset baggage and come from languages such as C# or Java or even more often laughed at as a toy.

For you who consider it daunting and hate working with it worry not! I will show you the most common missconceptions and all the patterns you need to know to become as fluent in JavaScript as you are in C#.

For you who consider it a toy language, something associated not with real programming but with copy-paste coding or scripting to add flare to websites, I will show you all the different patterns and programming paradigms that JavaScript supports and which make it just as good and powerful as C#.

Let’s get started!

JavaScript Quirks

One of the main things that missguides C# developers when they come to JavaScript is that while JavaScript looks like a C-like language, it does not behave like one in many ways. Four examples of these are: the unbecoming/unexpected behavior of this, that variables have function and not block scope, the strange phenomenon know as variable hoisting and the lack of explicit namespacing.

In the next few sections I will dive deeper into each of these quirks and try to save you some frustration the next time you write some JavaScript. And before you continue, you can find all the examples I use in this blog post in this jsFiddle, you can even play with the examples side by side with the article to get a better understanding of how JavaScript works.

This and JavaScript

One of the most common problems when a C# developer comes to JavaScript is that it expects this to work exactly as it does in C#. And She or He will write this code unaware of the dangers that lurk just an HTTP call away…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function UsersCatalog(){
    this.users = [];
    getUsers()

    function getUsers(){
        $.getJSON('https://api.github.com/users')
        .success(function(users){
            this.users.push(users);
            // BOOOOOOOM!!!!!
            // => Uncaught TypeError: Cannot read property 'push' of undefined
        });
    }
}
var catalog = new UsersCatalog();

Let’s see why this happens, how this works in JavaScript and we will round up and come back to this example at the conclusion once we have demystified this and become this-xperts.

So this in JavaScript is weird, and unlike other languages this depends on the context in which a function is invoked. This basically means that depending on how you call a function this will have a value or another:

  • this and objects
  • this unbound
  • this explicitly
  • this bound

This And Objects

In the most common scenario for an OOP developer we call a function as a method, that is a function that is a property within an object (using the dot notation as usual). In this case and as we would expect this will take the value of the object itself:

1
2
3
4
5
6
7
8
9
10
11
// #1. A function invoked in the context of an object (a method)
var hellHound = {
    attackWithFireBreath: function(){
        console.log(this + " jumps towards you and unleashes his terrible breath of fire! (-3 hp, +fear)");
    },
    toString: function (){ return 'Hellhound';}
}

hellHound.attackWithFireBreath();
// => Hellhound jumps towards you and unleashes his terrible breath of fire! (-3 hp, +fear)
// 'this' is the hellHound object

This Unbound

But you can also invoke a function without the context of its object:

1
2
3
4
5
6
7
// #2. A function invoked without the context of its object
var attackWithFireBreath = hellHound.attackWithFireBreath;
attackWithFireBreath();
// => [object Window] jumps towards you and unleashes his terrible breath of fire! (-3 hp, +fear)
// ups, 'this' is no longer the hellHound object but the Window object. What?
// By default the context of execution of a function is the Window object
// if you use strict mode it will be undefined => use strict mode

Whenever you invoke a function without an object as context the this automatically becomes the window object unless you have set strict mode on in which case this will take the value of undefined.

We could even take that very same function and add it to another object different from the original:

1
2
3
4
5
6
7
8
9
// we could add the same method to another object:
var jaime = {
    toString: function(){return 'jaime';}
};
jaime.attackWithFireBreath = attackWithFireBreath;

jaime.attackWithFireBreath();
// => jaime jumps towards you and unleashes his terrible breath of fire! (-3 hp, +fear)
// => 'this' is the jaime object

And again, when we invoke the original function in the context of an object, even another one different from the original one, this takes the value of that object.

This Explicitly

JavaScript Function prototype, from which all functions within JavaScript descend, provides two helpful methods that allow you to explicitly set the context within which a function is executed. These methods are call and apply and they work by taking the context (this) as an argument:

1
2
3
4
5
6
7
8
// #3. We can also explicitly set the context of execution of a function
// all functions have call and apply:
attackWithFireBreath.call(jaime /*, arg1, arg2, */);
// => jaime...
// => 'this' is jaime
attackWithFireBreath.apply(hellHound /*, [arg1, arg2, arg3...] */);
// => hell hound...
// => 'this' is hellHound

This Bound

And additionally, as of ECMAScript 5, the Function prototype also provides the bind function that lets us create new functions that always have a fixed context, that is, a fixed value for this.

It is important to note that bind will not alter the original function but will return a new function that is bound to the object given as an argument. Once a function is bound it is not possible to un-bound it nor re-bind it to another object (but you can always use the original unbound function):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// #4. And as of ES5 we can bind the context of execution of a function FOR EVER
attackBound = attackWithFireBreath.bind(hellHound);
attackBound();
// => Hellhound jumps towards you and unleashes his terrible breath of fire! (-3 hp, +fear)
// `this` is Hellhound even though I am not using the dot notation

// even if I give the function to another object
jaime.attackBound = attackBound;
jaime.attackBound();
// => Hellhound ...
// `this` is Hellhound even though I am using the dot notation with another object

// You cannot rebind a function that is bound
var attackReBound = attackBound.bind(jaime);
attackReBound();
// => Hellhound ...
attackBound();
// => hellHound ...

// But you can still bind the original
var attackRebound = attackWithFireBreath.bind(jaime);
attackRebound();
// => jaime...

Concluding This

So in summary, this can take different values based on how a function is invoked. It can:

  • Be an object if we call a function within an object with the dot notation
  • Be the window object or undefined (strict mode) if a function is invoked by itself
  • Be whichever object we pass as argument to call or apply
  • Be whichever object we pass as argument to bind.

And if now that you are a this-xperts you go back to the original example you will be able to easily spot the problem. Since the success function is not invoked in the context of our object, the UsersCatalog, this is not our original object. In this particular case this is the jqXHR object which for sure does not have a users property and thus the cannot read property of undefined error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function UsersCatalog(type){
    this.users = [];
    getUsers()

    function getUsers(){
        $.getJSON('https://api.github.com/users')
        .success(function(users){
            this.users.push(users);
            // BOOOOOOOM!!!!!
            // => Uncaught TypeError: Cannot read property 'push' of undefined
            // 'this' in this context is the jqXHR object
            // not our original object
        });
    }
}
var catalog = new UsersCatalog();

You can solve this issue in either of two ways. You can take advantage of JavaScript support for closures, declare a self variable that “captures” the value of this and use it within the closure function as depicted below (very common practice in JavaScript):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function UsersCatalogWithClosure(){
    "use strict";
    var self = this;

    self.users = [];
    getUsers()

    function getUsers(){
        $.getJSON('https://api.github.com/users')
        .success(function(users){
            self.users.push(users);
            console.log('success!');
        });
    }
}
var catalog = new UsersCatalogWithClosure();

Or you can use bind and ensure that the function that you use as callback is bound to the object that you want:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//#2. Using bind
function UsersCatalogWithBind(){
    "use strict";

    this.users = [];
    getUsers.bind(this)();

    function getUsers(){
        $.getJSON('https://api.github.com/users')
        .success(updateUsers.bind(this));
    }

    function updateUsers(users){
        this.users.push(users);
        console.log('success with bind!');
    }
}
var catalog = new UsersCatalogWithBind();

Function Scope and Variable Hoisting

Another interesting quirk about JavaScript is that, unlike many other languages, variables in JavaScript have function scope and not block scope. This can be better illustrated by the example below:

1
2
3
4
5
6
7
8
9
function aFunctiontoIllustrateFunctionScope(){

    if (true){
        var x = 10;
    }
    console.log(x);
}
aFunctiontoIllustrateFunctionScope();
// => 10 WAT

What happens in this example is that the JavaScript runtime hoists all variables within a function definition to the beginning of the function body. This means that the function that you’ve seen above it actually works like this:

1
2
3
4
5
6
7
8
9
10
11
function aFunctiontoIllustrateFunctionScope(){
    // hoisted variables
    var x = undefined;

    if (true){
        x = 10;
    }

    console.log(x);
    // => 10
}

And yet another example of hoisting:

1
2
3
4
5
6
7
8
9
10
11
function aFunctionToIllustrateHoisting(){
    // in reality
    // var i = undefined
    console.log('before i =' + i);
    // => before i = undefined
    for(var i = 0; i < 10; i++){
        // jara jara
    }
    console.log('after i = ' + i);
    // => after i = 10
}

And that’s the reason why JavaScript developers usually write all variable declarations in the beginning of a function, to be more explicit about what happens in reality when a given function is evaluated by the JavaScript runtime and avoid unnecessary bugs. Take a look at jQuery for instace:

1
2
3
4
5
6
7
8
9
10
/**
 * Load a url into a page
 */
jQuery.fn.load = function( url, params, callback ) {
    var selector, type, response,
        self = this,
        off = url.indexOf(" ");

    //... more codes
}

As a final note, you’ll be happy to hear that the next version of JavaScript ECMAScript 2015 introduces the let keyword that brings block scope variables to JavaScript.

Namespacing in JavaScript

As you will come to appreciate by the end of the series, JavaScript has a minimalistic design and a limited number of primitive constructs that can be used and composed to achieve higher level abstractions and constructs that are native to other languages, one of these being namespaces.

Since we do not have namespaces in JavaScript and yet we want to avoid declaring all of our variables in the global “namespace” (where they would be visible to every single module):

1
2
3
4
5
6
var dice = "d12";
dice;
// => d12
window.dice
// => d12
// ups... we are in the global scope/namespace

We use objects to emulate the construct of namespaces. A common pattern is depicted below where we use a IIFE (immediately invoked function expression) to create/augment a namespace:

1
2
3
4
5
6
7
8
9
10
11
// IIFE - we invoke the function expression as soon as we declare it
(function(armory){
    // armory being the namespace
    armory.sword = {damage: 10, speed: 15};
    armory.axe = {damage: 15, speed: 8};
    armory.mace = {damage: 16, speed: 7};
    armory.dagger = {damage: 5, speed: 20};

}(window.armory = window.armory || {} )); // either augment or create the armory namespace
console.log(armory.sword.damage);
// => 10

I will come back to namespacing and higher level code organization in JavaScript when we discuss JavaScript modules.

Summary

And that’s that for the first chapter of the JavaScript-mancy series. Hope that you have enjoyed and learned something new about JavaScript and if you already knew all this stuff, don’t worry, there are more exciting and interesting things coming like functional programming, cool OOP techniques and ES2015 (ES6), the next version of JavaScript.

Interested In Learning More JavaScript? Buy the Book!

Are you a C# Developer interested in learning JavaScript? Then take a look at the JavaScript-mancy book, a complete compendium of JavaScript for C# developers.

a JavaScriptmancy sample cover

Have a nice day!

More Articles in These Series

P.S. Did you know that these series started as a talk? Check Mastering the Arcane Art of JavaScript-mancy and other of my talk slides at SpeakerDeck.

Comments