barbarian meets coding

WebDev, UX & a Pinch of Fantasy

The Basic Ingredients of JavaScript-Mancy: An Introduction to JavaScript and ES 6 for C# Developers

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

I am Writing a Book!

Hi All! I am going to transmute the JavaScript-mancy series into book format and write the missing/ultimate JavaScript manual for C# developers with a pinch of humor and a bit of fantasy in the mix.

a JavaScriptmancy sample cover

I’ll bring you more news soon! In the meantime, the following is a draft of the first chapter of the book. Enjoy! And feedback is always welcomed!

An Introduction to JavaScript-Mancy

I expect the reader of this manuscript to be well acquainted with the basics of programming, but I couldn’t, in good faith, start the series without some sort of introduction to the arts of JavaScript. This first chapter therefore, will take you through the whole breadth of the JavaScript language, albeit in a superficial way. I will show you all the basic features of JavaScript, even those of its latest incarnation ECMAScript 6, and how they differ or are similar to C#. I abhorr starting a series with pages after pages on for loops and if statements so I will attempt to be as interesting, short and sweet and entertaining as I can.

JavaScript

JavaScript, as we the guardians of JavaScript-mancy usually call the arts, is a multi-paradigm dynamic programming language. The multi-paradigm bit means that JavaScript lends itself well to different styles (paradigms) of programming like object-oriented or functional programming. The dynamic part means that… well the dynamic part is widely disputed even today… but for all intents and purposes we can say that JavaScript is evaluated as it is executed, there’s no compilation step in which variables are bound, types are checked and expressions analyzed for correctness. The JavaScript runtime defers all this work until the code itself is being executed and this allows for a lot more freedom and interesting applications like metaprogramming 1.

JavaScript is also dynamically typed so a variable can reference many different types during its lifetime and you can augment objects with new methods or properties at any point in time.

I can summon a minion from the depths of hell, for example, and let it be a number using the var keyword:

1
2
3
> var minion = 1
> minion
// => 1

And I can do some alchemy thereafter and transform the minion into something else, a string, for example:

1
2
> minion = "bunny";
// => "bunny"

I can keep doing that for as long as I want (as long as I have enough mana of course):

1
2
> minion = {name: 'bugs', type: 'bunny'};
// => Object {name: 'bugs', type: 'bunny'}

An object in JavaScript isn’t defined by a blueprint class like in C# and I can augment 2 it with new properties to my heart’s content:

1
2
3
> minion.description = 'A mean looking bunny';
> console.log(minion);
// => Object {name: bugs, type: bunny, description: A mean looking bunny}

JavaScript Has Some Types

JavaScript supports the following types: Number, String, Object, Boolean, undefined, null and Symbol.

As you may have guessed, JavaScript has a single type to represent all numbers, which is pretty nice if you ask me, not having to ever think about doubles, and shorts, and longs and floats…

1
2
3
4
5
6
7
> var one = 1
> typeof(one)
// => "number"

> var oneAndAHalf = 1.5
> typeof(1.5)
// => "number"

There’s a string type that works as you would expect of any respectable string letting you store string literals. Interestingly enough, JavaScript strings support both single (') and double quotes ('):

1
2
3
4
5
6
7
> var text = "Thou shalt not pass!"
> text
// => "string"

> var anotherBitOfText = 'No! Thou Shalt Not Pass!'
> anotherBitOfText
// => "string"

It has a boolean type to represent true and false values:

1
2
3
4
> var always = true
> var never = false
> typeof(always)
// => "boolean"

And an object type that we can use to create any new custom types:

1
2
3
> var skull = {name: 'Skull of Dark Magic'}
> typeof(skull)
// => object

In a little bit uncommon fashion, JavaScript has two different ways of representing the lack of something. Where C# has null, JavaScript has both null and undefined. Unlike in C#, the default value of anything that hasn’t been yet defined is undefined, whereas null must be set explicitly.

1
2
3
4
5
6
7
8
> skull.description
// => undefined
> typeof(skull.description)
// => undefined

> skull.description = null;
> typeof(skull.description)
// => object :) 

ECMAScript 6 brings a new primitive type, the symbol. Symbols can be seen as constant and immutable tokens that can be used as unique IDs.

1
2
3
> var crux = Symbol()
> typeof(crux)
// => symbol

In future posts, we’ll see how we can use Symbols to enable new patterns for hiding data in JavaScript.

Everything Within JavaScript Behaves Like an Object

In spite of JavaScript not having the concept of value types or reference types, numbers, strings and booleans behave like C# value types and objects behave like C# reference types. In practice, however, everything within JavaScript can be treated as an object.

Numbers for instance, provide several useful methods:

1
2
3
4
5
6
> (1).toString()
// => 1
> (3.14159).toPrecision(3)
// => 3.141
> (5000).toLocaleString('sv-SE')
// => 5 000

And so do strings:

1
2
> "a ghoul".toUppercase()
// "A GHOUL"

Interesting right? If a number is a primitive value type, how come it has methods? Well, what is happening is that, whenever we call a method on a number or other primitive type, the JavaScript runtime is wrapping the primitive value in a special wrapper object. So even though 1 is not an object itself, when JavaScript evaluates (1).toPrecision(3) it wraps the value within the Number object on-the-fly. You can test the reverse process and instantiate a number using the wrapper object directly:

1
2
3
4
> var number = new Number(1);
// => Number {}
> typeof(number)
// => 'object'

Then unwrap the original value with valueOf:

1
2
> number.valueOf()
// => 1

Even more remarkable than numbers and strings, functions behave like objects. They have their own methods:

1
2
3
> var fireBall = function(){ world.spell('A blazing ball of fire materializes from the palm of your hand!');};
> fireBall.apply
// => function apply(){}

And you can even add properties to a function:

1
2
3
4
> fireBall.maxNumberOfCharges = 5
// => 5;
> fireBall.maxNumberOfCharges
// => 5;

Let’s take a quick look at each one of these types and how they work in JavaScript.

Strings in JavaScript

Strings, like in C#, let you represent text literals.

1
2
3
4
5
6
> "hi there"
// => hi there
> "creepy"
// => creepy
> "stop repeating what I say"
// => stop repeating what I say

Unlike in C# you can use both single (') and double quotes (") to create a string. Oftentimes you will see one used to escape the other:

1
2
3
4
> "this ain't cool man"
// => this ain't cool man
> 'you think you are so "funny"'
// => you think you are so "funny"

Any string has a number of useful methods:

1
2
3
4
5
6
> "I am tired of you devious REPL".split(' ');
// => ["I", "am", "tired", "of", "you", "devious", "REPL"]
> "I am tired of you devious REPL".replace('tired', 'ecstatic');
// => I am ecstatic of you devious REPL
> "I am tired of you devious REPL".indexOf('tired');
// => 5

ES6 also brings a number of new methods like startsWith, endsWith, repeat:

1
2
3
4
5
6
7
8
> "Stop REPL!".startWith("Stop");
// => true
> "Stop REPL!".endsWith("REPL!");
// => true
> "NaN".repeat(10) + " BatMan!!!"
// => NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN BatMan!!!!
> "ha! Now I beat you at your own game!"
// => "ha! Now I beat you at your own game!"

Until recently, there was no such thing as C# String.format nor StringBuilder so most injecting values in strings was done using the + operator or string.concat:

1
2
3
4
5
> var target = 'minion';
> "obliterate " + target + " with hellfire!"
// => obliterate minion with hellfire!
> "obliterate ".concat(target, " with hellfire!")
// => obliterate minion with hellfire!

Fortunately, ES6 brings template strings with much more elegant approach to string interpolation.

Better String Interpolation ES6 Template Strings

The new ES6 Template Strings improve greatly the way you can operate with strings. They allow string interpolation based on the variables that exist in the scope where the template is evaluated, thus providing a much cleaner and readable syntax.

In order to create a template string you surround the string literal with backticks `` and use${variable-in-scope}` to specify which variable to include within the resulting string:

1
2
3
> var spell = 'hellfire';
> `obliterate ${target} with ${spell}!`
// => obliterate minion with hellfire!

Template strings also let you easily create multi-line strings. Whereas before you would be forced to make use of string concatenation and the new line character \n:

1
2
3
4
5
6
7
8
> "One ring to rull them all\n" +
  "One ring to find them;\n" +
  "One ring to bring them all\n" +
  "and in the darkness bind them"
// =>  One ring to rull them all
       One ring to find them;
       One ring to bring them all
       and in the darkness bind them

ES6 Template strings let you write a multi-line string in a much more straightforward fashion:

1
2
3
4
5
6
7
8
> `One ring to rull them all
  One ring to find them
  One ring to bring them all
  and in the darkness bind them`
// =>  One ring to rull them all
       One ring to find them;
       One ring to bring them all
       and in the darkness bind them

Functions in JavaScript

Functions are the most basic building component in JavaScript. As such, they can live more independent lives than methods in C# which are always tied to a class. So, you’ll oftentimes see functions alone in the wild:

1
2
3
4
5
> function obliterate(target){
    console.log(`${target} is obliterated into tiny ashes`);
}
> obliterate('rabid bunny')
// => rabid bunny is obliterated into tiny ashes

In JavaScript, in a radically different approach to C#, lets you call a function with any number of arguments, even if they are not defined in a functions signature:

1
2
> obliterate('rabid bunny', 'leprechaun', 'yeti')
// => rabid bunny is obliterated into tiny ashes

And even with no arguments at all, although depending on the function implementation it may cause some chaos and some mayhem:

1
2
> obliterate()
Uncaught ReferenceError: hello is not defined

You can use the very special arguments array-like object to get hold of the arguments being passed at runtime to a given function:

1
2
3
4
5
6
7
> function obliterateMany(){
    // ES6 method to convert arguments to an actual array
    var targets = Array.from(arguments).join(', ');
    console.log(`${targets} are obliterated into tiny ashes`);
}
> obliterate('Rabid bunny', 'leprechaun', 'yeti')
// => Rabit bunny, leprechaun, yeti are obliterated into tiny ashes

Or the finer ES6 rest syntax reminescent of C# params:

1
2
3
4
5
6
> function obliterateMany(...targets){
    var targets = Array.from(arguments).join(', ');
    console.log(`${targets} are obliterated into tiny ashes`);
}
> obliterate('Rabid bunny', 'leprechaun', 'yeti')
// => Rabit bunny, leprechaun, yeti are obliterated into tiny ashes

In addition to functions working as… well… functions, functions perform many other roles in JavaScript and are oftentimes used as building blocks to achieve higher-order abstractions: they are used as object constructors, to define modules, as a means to achieve data hiding and have many other uses.

ES6 changes this complete reliance in functions a little bit as it provides new higher level constructs that are native to the language, constructs like ES6 classes and ES6 modules which you’ll be able to learn more about within future posts in this series. Indeed throughout this manuscript I’ll show you both ES5 constructs, the present and the past, and ES6 ones, the present-ish and the future, so you can defend yourselve equally well in any JavaScript codebase you happen to work with.

Functions as Values

An interesting and very important aspect of functions in javascript is that they can be treated as values, this is what we mean when we say functions are first-class citizens of the language. It means that they are not some special construct that you can only use in certain places, with some special conditions and grammar. Functions are just like any other type in JavaScript, you can store them in variables, you can pass them as arguments to other functions and you can return them from a function.

For instance, let’s say you want to create a very special logger that prepends your name to any message that you wish to log:

1
2
3
4
5
6
> var log = function(msg){ console.log(msg);}
> var logByRandalf = function (msg, logFn){
    logFn(Randalf logs: `${msg}`);
}
> logByRandalf('I am logging something, saving it to memory for ever', log);
// => Randalf logs: I am logging something, saving it to memory for ever

But that was a little bit awkward, what if we return a function with the new functionality that we desire:

1
2
3
4
5
6
7
8
> var createLogBySomeone = function (byWho){
    return function(msg){
        return console.log(Randalf logs: `${msg}`);
    };
}
> var logByRandalf = createLogBySomeone('Randalf');
> logByRandalf('I am logging something, saving it to memory for ever');
// => Randalf logs: I am logging something, saving it to memory for ever

If you feel a little bit confused by this don’t worry, we will dive deeper into functional programming, closures, high-order functions later within the series and everything will become much clearer then. For now just realize that functions are values and you can use them as such.

JavaScript Has Function Scope

Another very interesting aspect of JavaScript that is diametrically opposed to how things work in C# is the scope of variables. JavaScript variables have function scope and not block scope. This means that functions define new scopes for variables and not blocks of code (if statements, for loops, *code between {}, etc) which highlights once more the importance of functions in JavaScript.

You can appreciate function scope in all its glory in these examples. First if you declare a single function with an if block you can verify how the if block doesn’t define a new scope as you would expect in C#:

1
2
3
4
5
6
7
> function scopeIsNuts(){ // new scope for scopeIsNuts
    console.log(x); // => undefined
    if (true){
        var x = 1;
    }
    console.log(x); // => 1
}

But if we replace the if block with a new function inner, then we have two scopes:

1
2
3
4
5
6
7
8
9
10
11
12
> function outer(){ // new scope for outer
    var x = 0;
    console.log(x); // => 0

    function inner(){ // new scope for inner
        var x = 1;
        console.log(x); // => 1
    }
    inner();

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

ES6 let, ES6 const and Block Scope

ES6 attemps to bring an end to the confussion of JavaScript having function scope with the let keyword that lets you create variables with block scope. With ES6 you can either use var for function scoped variables or let for block scoped ones.

If you rewrite the example we used to illustrate function scope with let, you’ll obtain a very different result:

1
2
3
4
5
6
7
8
> function scopeIsNuts(){ // new scope for scopeIsNuts
    console.log(x); // => undefined
    if (true){
        let x = 1;
        console.log(x); // => 1
    }
    console.log(x); // => undefined
}

Now the x variable only exists within the if statement block. Additionally, you can use the const keyword to declare constant variables with block scope.

1
2
3
4
5
6
7
8
9
> function scopeIsNuts(){ // new scope for scopeIsNuts
    console.log(x); // => undefined
    if (true){
        const x = 1;
        console.log(x); // => 1
        x = 2; // => TypeError
    }
    console.log(x); // => undefined
}

ES6 Default Arguments

ES6 finally brings default arguments to JavaScript functions, and they work just like in C#:

1
2
3
4
5
6
7
8
> function fireBall(target, mana=10){
   var damage = 1.5*mana;
   console.log(`A huge fireball springs from your fingers and hits the ${target} with ${damage} damage`);
}
> fireBall('troll')
// => A huge fireball springs from your fingers and hits the troll with 15 damage
> fireBall('troll', /* mana */ 50)
// => A huge fireball springs from your fingers and hits the troll with 75 damage

ES6 Destructuring

Another nifty ES6 feature is destructuring. Destructuring lets you unwrap any given object into a number of properties and bind them to variables of your choice. You can take advantage of destructuring with any object:

1
2
3
4
5
> var {hp, defense} = {name: 'conan', description: 'cimmerian barbarian king of thieves', hp: {current: 9000, max: 9000}, defense: 100, attack: 400};
> console.log(hp);
// => {current: 9000, max: 9000}
> console.log(defense);
// => 100

Even when passing an object to a function:

1
2
3
4
5
6
7
8
9
10
11
12
> function calculateDamage({attack}, {hp, defense}){
    var effectiveAttackRating = attack - defense + getHpModifier(hp);
    var damage = attackRoll(effectiveAttackRating);
    return damage;

    function getHpModifier(hp){ return hp.current < 0.1*hp.max ? 10 : 0;}
    function attackRoll(dice){ return dice; } // do some fancy dice rolling 
}
> var troll = {name: 'Aaagghhhh', description: 'nasty troll', hp: {current: 20000, max: 20000}, defense: 40, attack: 100};
> calculateDamage(troll, conan);
// => 0
// => no troll gonna damage conan

ES6 Arrow Functions

Another great feature brought by ES6 are arrow functions which resemble C# lambda expressions. Instead of writing the obliterate function as we did before, we can use the arrow function syntax:

1
2
3
4
5
6
7
8
9
/* 
> function obliterate(target){ 
    console.log(`${target} is obliterated into tiny ashes`);
}
*/
> let obliterate = target => console.log(`${target} is obliterated`);
obliterate('minion');
> obliterate('rabid bunny')
// => rabid bunny is obliterated into tiny ashes

And if you have a function with more arguments or statements, you can write it just like we do in C#:

1
2
3
4
5
6
> let obliterateMany = (...targets) => {
    let targets = targets.join(', ');
    console.log(`${targets} are obliterated into tiny ashes`);
};
> obliterateMany('bunny', 'leprechaun', 'yeti');
// => Bunny, leprechaun, yeti are obliterated into tiny ashes

We will dive deeper into arrow functions later within the series and see how they not only provide a terser and more readable syntax but also serve a very important function in what regards to safekeeping the value of this in JavaScript. (We’ve got ourselves a very naughty this in JavaScript as you’ll soon appreciate yourself)

OOP and Objects in JavaScript

JavaScript has great support for object-oriented programming with objects literals, constructor functions, prototypical inheritance, ES6 classes and less orthodox OOP paradigms like mixins and stamps.

Objects in JavaScript are just key/value pairs. The simplest way to create an object is using an object literal:

1
2
3
4
5
6
7
> var scepterOfDestruction = {
    description: 'Scepter of Destruction',
    toString: function() { return this.description; }
    destruct: function(target) { console.log(`${target} is instantly disintegrated`);}
}
> scepterOfDestruction.destruct('apple');
// => apple is instantly disintegrated

ES6 makes easier to create object literals with syntactic sugar for functions:

1
2
3
4
5
> var scepterOfDestruction = {
    description: 'Scepter of Destruction',
    toString() { return this.description; },
    destruct(target) { console.log(`${target} is instantly disintegrated`);}
}

And for creating properties from existing variables:

1
2
3
4
5
6
7
8
9
> var damage = 10000;
> var scepterOfDestruction = {
    description: 'Scepter of Destruction',
    damage, // as opposed to damage: damage
    toString() { return this.description; },
    destruct(target) { console.log(`${target} is instantly disintegrated`);}
}
> scepterOfDestruction.damage;
// => 10000

This works great for one-off objects. When you want to reuse the same type of object more than once you can either use a vanilla factory method or a constructor function with the new keyword:

1
2
3
4
5
6
7
8
9
10
// by convention constructor functions are capitalized
> function Scepter(name, damage, spell){
    this.description = `Scepter of ${name}`,
    this.damage = damage;
    this.castSpell = spell;
    this.toString = () => return this.description;
}
> var scepterOfFire = new Scepter('Fire', 100, (target) => console.log(`${target} is burnt to cinders`);
> scepterOfFire.castSpell('grunt');
// => grunt is burnt to cinders

Prototypical Inheritance

Yet another big diffence between C# and JavaScript are their inheritance models. JavaScript exhibits what is know as prototypical inheritance. That means that objects inherit from other objects which therefore are called prototypes. These objects create what is know as a prototypical chain that is traversed when the JavaScript runtime tries to determine where in the chain a given method is defined.

Let’s say that you have an object that represents an abstraction for any item that can exist in your inventory:

1
2
3
4
5
6
7
> var item = {
   durability: 100,
   sizeInSlots: 1,
   toString(){ return 'an undescriptive item';}
}
> item.toString();
// => an undescriptive item

And a two handed iron sword that in addition to being an item (and an awesome item at that) has its own specific set of traits:

1
2
3
4
5
6
7
> var ironTwoHandedSword = {
    damage: 60,
    sizeInSlots: 2,
    wield() { console.log('you wield your iron sword crazily over your head');},
    material: 'iron',
    toString() {return 'A rusty two handed iron sword';}
};

You can take advantage of JavaScript prototypical inheritance to reuse the item properties across may items, by setting the item object as the prototype of the ironTwoHandedSword (and any other specific items that you create afterwards).

1
> ironTwoHandedSword.prototype = item;

This will establish a prototypical chain, so that, if we attempt to retrieve the sword durability, JavaScript runtime will traverse the chain and retrieve the property from the item prototype:

1
2
> ironTwoHandedSword.durability;
// => 100

If, on the other hand, you attemp to access a property that exists in both the prototype and the object itself, the nearest property in the chain will win:

1
2
> ironTwoHandedSword.toString();
// => A rusty two handed iron sword

ES6 exposes the __proto__ property that lets you directly assign a prototype through an object literal:

1
2
3
4
5
6
> var ironTwoHandedSword = {
    __proto__: item
    damage: 60,
    // etc...
};
> ironTwoHandedSword.prototype = item;

There’s a lot more to prototypical inheritance and the many different OOP paradigms supported by JavaScript. But we’ll look further into them later in the series.

ES6 Classes

A new addition to JavaScript you might have heard about and celebrated are ES6 classes. The existence of ES6 classes doesn’t mean that JavaScript gets classes just like C# and we’re not going to worry about constructor functions and prototypical inheritance anymore. ES6 classes are “just” syntactic sugar over the existing inheritance model and the way we craft objects in JavaScript. That being said, it is a great declarative way to represent constructor/prototype pairs.

A JavaScript class looks very similar to a C# class:

1
2
3
4
5
6
7
8
9
10
11
12
> class Item {
    constructor(durability = 100, sizeInSlots = 1){
      this.durability = durability;
      this.sizeInSlots = sizeInSlots;
    }
    toString(){
      return 'an undescriptive item';
    }
}
> var item = new Item();
> item.toString();
// => an undescriptive item

And so does inheritance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> class Sword extends Item {
    constructor(durability = 500, sizeInSlots = 2, damage = 50, material = 'iron'){
      super(durability, sizeInSlots);
      this.damage = damage;
      this.material = material;
    }
    wield() {
      console.log(`you wield your ${this.material} sword crazily over your head`);
    }
    toString() {
      return `A ${this.material} sword`;
    }
};
> var sword = new Sword();
> sword.wield();
// => you wield your iron sword crazily over your head

Arrays, Maps and Sets in JavaScript

Up until recently JavaScript had only one single data structure, albeit very verstatile, to handle collections of items: the array. You can create an array using using square brackets []:

1
2
> [1, 2, 3, 4 ,5]
// => [1,2,3,4,5]

You can mix and match the different elements of an array. There’s no type restrictions so you can have numbers, strings, objects, functions, arrays, etc

1
2
3
4
5
6
7
> var aKendersPoach = [
    'jewel',
    '3 stones',
     1,
    {name: 'Orb of Power}, 
    function() { return 'trap!';}
    ];

You can access the items of an array via their indexes:

1
2
3
4
> aKendersPoach[0]
// => jewel
> aKendersPoach[4]()
// => trap!

You can traverse the indexes of an array using the for/in loop:

1
2
3
4
5
> for (var idx in aKendersPoach) console.log(aKenderPoach[idx]);
// => jewel
// => 3 stones
// => ...etc
// => function() { return 'trap!';}

And even better the items of an array using ES6 for/of loop:

1
2
3
4
5
> for (var item of aKendersPoach) console.log(item);
// => jewel
// => 3 stones
// => ...etc
// => function() { return 'trap!';}

Arrays have a lot of cool and useful methods that you can use to add/remove or otherwise operate on the items within the array:

1
2
3
4
5
6
7
8
9
10
11
12
> aKendersPoach.length
// => 5
> aKendersPoach.push('silver coin');  // add item at the end of the array
// => 6 (returns the current length of the array)
> aKendersPoach.push('6 copper coins', 'dental floss');
// => 8
> aKendersPoach.pop(); // pop item at the end of the array
// => dental floss
> aKendersPoach.unshift('The three Musketeers'); // insert item in the beginning
// => 8
> aKendersPoach.shift(); // extract item from the beginning of the array
// => 'The three musketeers'

And even LINQ-like methods to perform functional style transformations within an array:

1
2
3
4
5
> var goldCoins = aKendersPoach
                     .filter(isValuable) // ES6 analogous to LINQ Where
                     .map(toGoldCoins) // analogous to LINQ Select
                     .reduce(sumCoins); // analogous to LINQ Aggregate
// => 7

You will learn a ton more about arrays and JavaScript versions of LINQ later in the series.

ES6 Spread Operator and Arrays

The ES6 spread operator can also be used to merge an array within another array, or otherwise called, flatten an array inside another:

1
2
3
4
> var newRecruits = ['Sam', 'John', 'Connor'];
> var merryBandits = ['Veteran Joe', 'Brave Krom', ...newRecruits];
> merryBandits;
// => ["Veteran Joe", "Brave Krom", "Sam", "John", "Connor"]

ES6 Maps and Sets

ES6 gives us magicians two new data structures to work with: maps, a true key/value pair data structure and sets to handle collections of unique items.

You can create a new map using the Map constructor:

1
2
3
4
> var libraryOfWisdom = new Map();
> libraryOfWisdom.set(A, ['A brief history of JavaScript-mancy', 'A Tale of Two Cities');
> libraryOfWisdom.get('A')
// => ['A brief history of JavaScript-mancy', 'A Tale of Two Cities']; 

You can even seed a map with existing information by sending an array of key/value pairs3:

1
2
3
4
5
6
> var libraryOfWisdom = new Map([
    ['A', ['A brief history of JavaScript-mancy', 'A Tale of Two Cities']],
    ['B', ['Better Dead Than Powerless: Tome I of Nigromantics']]
]);
> libraryOfWisdom.get('B');
// => ['Better Dead Than Powerless: Tome I of Nigromantics']

In a similar fashion, you create sets using the Set constructor:

1
2
3
> var powerElements = new Set(['earth', 'fire', 'water', 'wind']);
> powerElements
// => Set {"earth", "fire", "water", "wind"}

Sets will ensure that you don’t have duplicated data within a collection:

1
2
3
> powerElements.add('water').add('earth').add('iron');
> console.log(powerElements);
// => Set {"earth", "fire", "water", "wind", "iron"}

JavaScript Flow Control

JavaScript gives you the classic flow control structures that you are accostumed to in C#: if, for, while loops behave much in the same way in JavaScript than in C# (bur for the function scope variables of course).

In addition to these, JavaScript has the for/in loop that lets you iterate over the properties of an object:

1
2
3
4
5
> var spellOfFarseeing = { name: 'Spell of Farseeing', manaCost: 10, description: 'The spell lets you see a limited portion of a far away location;'}
> for (var prop in spellOfFarseeing) console.log(`${prop} : ${spellOfFarseeing[prop]}`);
// => name : Spell of Farseeing
// => manaCost : 10
// => description : The spell lets you see a limited portion of a far away location

And the ES6 for/of loop that lets you iterate over collections4 (arrays, maps and sets):

1
2
3
4
5
> for (var element of powerElements) console.log(element);
// => earth
// => fire
// => water
// => etc...

Logical Operators in JavaScript

Abstract Equality and Strict Equality

JavaScript equality operators behave in a particular special way. The operators that you are accostumed to use in C# == and != are called abstract equality operators and evaluate the equality of expressions in a loose way. If the two expressions being evaluated by one of this operators don’t match in type, they’ll be converted resulting to a matching type. For instance, in evaluating the abstract equality of 42 and "42", the string will be converted to a number resulting in both values being equal:

1
2
> 42 == '42'
==> true

Fortunately JavaScript also provides operators that performs strict equality ( === and !==) which is basically a comparison of two values without the implicit type conversion.

1
2
> 42 === '42'
==> false

Implicit Type Conversion Also Know As Type Coercion

This implicit conversion that takes place in JavaScript gives birth to the concept of truthy and falsey. Since any value can be evaluated as a boolean, we say that some values like an array [] or an object {} are truthy, and some other values like empty string '' or undefined are falsey. In the examples below we use the !! to explicitly convert values to boolean:

1
2
3
4
5
6
7
8
9
10
11
12
> !![]
// => true
> !!{}
// => true
> !!""
// => false
> !!undefined
// => false
> !!null
// => false
> !!0
// => false

This allows for a terser way to write if statements

1
> if (troll) // as opposed to (troll != null && troll != undefined)

OR and AND

OR (||) and AND (&&) operations also behave in an interesting way. The OR operation will return the first truthy expression or the last falsey expression (if all expressions are falsey):

1
2
3
4
5
6
7
// 0 falsey
// 'cucumber' truthy
// 42 truthy
> 0 || 'cucumber' || 42
// => 'cucumber'
> 0 || false || undefined
// => undefined

The AND operator will return the last truthy expression or the first falsey expression (if any falsey expression is encountered):

1
2
3
4
5
6
7
// 0 falsey
// 'cucumber' truthy
// 42 truthy
> 0 && 'cucumber' && 42
// => 0
> true && 'cucumber' && 42
// => 42

Exception Handling

Exception handling works similar as in C#, you have your familiar try/catch/finally blocks:

1
2
3
> try { asdf; } catch (e) { console.log(e.message);} finally { console.log('done!');}
// => asdf is not defined
// => done!

And you can throw new exceptions with the throw keyword:

1
2
> throw new Error("We're all gonna die!");
// => Uncaught Error: We're all gonna die!

Additionally you can improve your error semantics and create custom errors by inheriting the Error prototype.

Regular Expressions

JavaScript also supports regular expressions. You can create a regular expression in two ways, either by wrapping the expression between slash /:

1
2
3
4
5
> var matchNumbers = /\d+/;
> matchNumbers.test('40 gold coins');
// => true
> matchNumbers.exec('40 gold coints');
// => ["40"]

Or by creating a RegExp object:

1
2
3
4
5
> var matchItems = new RegExp('\\D+');
> matchItems.test('40 gold coins');
// => true
> matchItems.exec('40 gold coints');
// => [" gold coins"]

Strings have built-in support for regular expressions as well with the match and search methods:

1
2
3
4
5
> var bagOfGold = '30 gold coins';
> bagOfGold.match(/\d+/);
// => ['30']
> bagOfGold.search(/\d+/);
// => 0 (index where first match is found)

But Beware, JavaScript Can Be Weird and Dangerous

So far you’ve seen the bests parts of JavaScript and nothing too weird or inconsistent. But sometimes you’ll experience strange behaviors in some less visited corners of JavaScript like any of the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> x = 10;
// => added a variable to the global scope (window.x)
> NaN == NaN
// => false
> null == undefined
// => true
> typeof(null)
// => object
> [] + []
// => ''
> [] + {}
// => {}
> {} + []
// => 0
> {} + {}
// => NaN

Oftentimes you won’t run into this issues when building real web applicatins and my advice is that you ignore them. Be aware that they exist but just don’t use them, or use patterns or conventions to avoid them.

Summary

And that was a summary of pretty much the whole JavaScript language. We’ve seen that JavaScript is a very flexible dynamic language with a lot of great features.

We have seen the many things you can do with strings and ES6 string templates. How functions are a very independent entities and a fundamental building block of applications in JavaScript, as well as arrow runctions that resemble lambdas in C#. We took a look at objects in JavaScript, protypical inheritance and ES6 classes. We saw the different data structures supported in JavaScript, the versatility of the array and an overview of the new ES6 Map and Set.

We also took a look at more general language features like the flow control structures and logical operators. We saw how JavaScript has similar flow control structures to C# and, in addition, the for/in for object properties and for/of loops analog to C#’s foreach. We saw the difference between abstract comparison and strict comparison in JavaScript, highlighted the implicit type conversion inherent to JavaScript, the existence of the concepts of truthy and falsey and the way the OR and AND operators work.

Finally we reviewed JavaScript exception handling and regular expressions, and we saw some of the weird and best-avoided behaviors in 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

More Articles in These Series


  1. This is a gross oversimplification. If you’ve read some traditional literature about static vs dynamic programming languages you’ll be familiar with the idea that static programming languages like C++, Java, C# are compiled and then executed whereas dynamic programming languages like Ruby, Python or JavaScript are not compiled but interpreted on-the-fly as they are executed. The repercussions of this being that a compiled program cannot be changed at runtime (you would need to recompile it), whereas an interpreted one can since nothing is set in stone until it is run. In today’s world however, JavaScript runtimes like V8(Chrome) or SpiderMonkey(Mozilla) compile JavaScript to machine code, optimize it, and re-optimize it based on heuristics on how the code is executed.

  2. As an article of interest you can augment objects in C# if you use the dynamic keyword with ExpandoObjects

  3. in reality, it does not need to be an array, but an iterable that produces key/value pairs [<key>:<value>]

  4. for the sake of correctness, you can use the for/of loop not only on arrays, maps and sets but on anything that implements the iterable protocol. We will discuss iterability later within the series.

Comments