JavaScript-mancy: Getting Started Preview - JavaScript Basics

JavaScript Basics

The Essential Ingredients Of JavaScript-Mancy

The importance of the fundamentals cannot be enough overstated,
the gathering of the proper ingredients for an incantation,
the carefulness and caring of the preparations,
the timing and intimate knowledge of the rituals,
everything affects the end result.

To practice is to be,
practice as you want to be,
for do you want to be an Artful Wizard, or a mediocre one?

Kely Sompsin,
Maester of the Guild, Fourth Age

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 book without some sort of introduction to the arts of JavaScript. This first chapter will therefore 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 programming books with page after page on for loops and if statements so I will attempt to be as brief, interesting and entertaining as I can.

If you feel like you are well versed in the basics of JavaScript (and the new ES6 features) then by all means jump over this chapter, but be aware that there’s a story happening in the examples, so you might be interested in taking a look. In any case, here we go…

/*

And so here are we... at the start of a new adventure,
our heroine sleeping peacefully in the middle of a clearing, 
surrounded by the darkness of a moonless night.

We will call her... *stranger* since we do not yet know her name...

*/

stranger.says('hmmm... what?! where!?');
stranger.weaves('Console.WriteLine("lux++!")');
// => Uncaught ReferenceError: Console is not defined

stranger.says('hmm?');
stranger.weaves('Console.WriteLine("lux = lux + 1 !!")');
// => Uncaught ReferenceError: Console is not defined

/*

The stranger curses and looks startled. Well I suppose she looks 
startled, it is hard to see a person's expression in the complete 
blackness of a moonless night as you well know...

*/

randalf.says("I'm afraid that is not going to work here...");
randalf.weaves("lux();");
// => A tiny wisp of light appears out of thin air and 
//    illuminates the surroundings

/* 

Ok, now! THAT, my friend, is what startled looks like!");

*/

randalf.says("Hmm, you are not ready yet...no...no... " + 
   "You are going to need to learn some ~~~JavaScript~~~");

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, for example, summon a minion from the depths of hell using the var keyword and let it be a number:

> var minion = 1
> minion
// => 1

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

> minion = "bunny";
// => "bunny"

I can keep doing that for as long as I want (as long as I have enough mana2 of course), so let’s make my minion an object:

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

In JavaScript I don’t need a class to create an object. I can just create an object with whichever properties I desire and then later on augment 3 it with new properties to my heart’s content:

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

> 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 any respectable string to behave. It lets you create string literals. Interestingly enough, JavaScript strings support both single (') and double quotes ("):

> var text = "Thou shalt not pass!"
> typeof text
// => "string"

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

JavaScript also has a boolean type to represent true and false values:

> var always = true
> var never = false
> typeof(always)
// => "boolean"

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

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

JavaScript differs from other languages in that it 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.

> skull.description
// => undefined
> typeof(skull.description)
// => undefined

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

This can get even more confusing because of the fact that there’s a third possibility. That a variable hasn’t been declared:

> abracadabra
// => Uncaught ReferenceError: abracadabra is not defined

The confusion coming mainly from the error message: abracadabra is not defined. You can just think about these variables as undeclared instead of not defined and stick to the previous definition of undefined.

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.

> var crux = Symbol()
> typeof(crux)
// => symbol

Later within the book, 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).toString()
// => 1
> (3.14159).toPrecision(3)
// => 3.141
> (5000).toLocaleString('sv-SE')
// => 5 000

And so do strings:

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

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

Then unwrap the original value with valueOf:

> number.valueOf()
// => 1

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

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

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

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

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

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

> "Stop REPL!".startsWith("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:

> 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 and a 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:

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

Template strings also let you easily create multi-line strings.

Where in the past you were forced to make use of string concatenation and the new line character \n:

> "One ring to rule 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 more straightforward fashion:

> `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:

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

JavaScript, in a radically different way than C#, lets you call a function with any number of arguments, even if they are not defined in a function’s signature:

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

> obliterate()
// => undefined is obliterated into tiny ashes

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

> 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')
// => Rabid bunny, leprechaun, yeti are obliterated into tiny ashes

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

> function obliterateMany(...targets){
    console.log(`${targets} are obliterated into tiny ashes`);
}
> obliterate('Rabid bunny', 'leprechaun', 'yeti')
// => Rabid bunny, leprechaun, yeti are obliterated into tiny ashes

In addition to functions working as… well… functions, they 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 on 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 later in this series. Indeed throughout this series I’ll show you both ES5 constructs, the present and the past, and ES6 ones, the present-ish and the future, so you’ll feel at home 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:

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

> var createLogBySomeone = function (byWho){
    return function(msg){
        return console.log(`${byWho} 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 and high-order functions later in the series. 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#:

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

> 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 confusion of JavaScript having function scope with the let keyword that allows you to 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:

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

> 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#:

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

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

function calculateDamage({attack}, {hp, defense}){
  var effectiveAttackRating = attack - defense + getHpModifier(hp);
  var damage = attackRoll(effectiveAttackRating);
  return damage > 0 ? damage: 0;

  function getHpModifier(hp){ 
    return hp.current < 0.1*hp.max ? 10 : 0;
  }

  function attackRoll(dice){ 
    // do some fancy dice rolling 
    return dice; 
  } 
}

var troll = {
  name: 'Aaagghhhh', 
  description: 'nasty troll', 
  hp: {current: 20000, max: 20000}, 
  defense: 40, attack: 100
};
var conan = {name: 'conan', 
  hp: {current: 200, max: 200}, 
  defense: 1000, attack: 1000
};
console.log(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:

/* 
> function obliterate(target){ 
    console.log(`${target} is obliterated into tiny ashes`);
}
*/
> let obliterate = target => 
    console.log(`${target} is obliterated into tiny ashes`);
> obliterate('minion');
// => minion is obliterated into tiny ashes
> 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#:

> let obliterateMany = (...targets) => {
    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 in the book 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:

> 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 also known as method shorthand:

> 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 also known as property shorthand:

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

// by convention constructor functions are capitalized
> function Scepter(name, damage, spell){
    this.description = `Scepter of ${name}`,
    this.damage = damage;
    this.castSpell = spell;
    this.toString = () => 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 known as prototypical inheritance. That means that objects inherit from other objects which therefore are called prototypes. These objects create what is known 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:

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

> 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 many items, by setting the item object as the prototype4 of the ironTwoHandedSword (and any other specific items that you create afterwards).

> Object.setPrototypeOf(ironTwoHandedSword, item);

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

> ironTwoHandedSword.durability;
// => 100

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

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

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

> 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 into them further 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:

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:

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, 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… in much the same way that you can find the most strange items in a kender’s 5 pouch:

> var aKendersPouch = [
    'jewel', 
    '3 stones', 
     1, 
    {name: 'Orb of Power'}, 
    function() { return 'trap!';}
    ];

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

> aKendersPouch[0]
// => jewel
> aKendersPouch[4]()
// => trap!

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

> for (var idx in aKendersPouch) console.log(aKendersPouch[idx]);
// => jewel
// => 3 stones
// => ...etc
// => function() { return 'trap!';}

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

> for (var item of aKendersPouch) 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:

> aKendersPouch.length
// => 5

// add item at the end of the array
> aKendersPouch.push('silver coin');  
// => 6 (returns the current length of the array)
> aKendersPouch.push('6 copper coins', 'dental floss');
// => 8

// pop item at the end of the array
> aKendersPouch.pop(); 
// => dental floss

// insert item at the beginning
> aKendersPouch.unshift('The three Musketeers'); 
// => 8

// extract item from the beginning of the array
> aKendersPouch.shift(); 
// => 'The three musketeers'

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

> const isValuable = item => parseInt(item) > 5;
> const toGoldCoins = item => parseInt(item) || 0;
> const sumCoins = (sum, price) => sum + price;

> var goldCoins = aKendersPouch
                     .filter(isValuable) // ES6 analogous to LINQ Where
                     .map(toGoldCoins) // analogous to LINQ Select
                     .reduce(sumCoins, 0); // analogous to LINQ Aggregate
> console.log(goldCoins);
// => 6

You will learn a ton more about arrays later in the book.

ES6 Spread Operator and Arrays

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

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

> 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 pairs6:

> var libraryOfWisdom = new Map([
 ['A', ['A brief history of JavaScript-mancy', 'A Tale of ...']],
 ['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:

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

> 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 accustomed to: if, for, while loops behave much in the same way in JavaScript than in C# (but for the function scoped variables of course).

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

> 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 collections7 (arrays, maps and sets):

> 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 particularly special way. The operators that you are accustomed 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 these operators don’t match in type, they’ll be converted 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:

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

> 42 === '42'
==> false

Implicit Type Conversion Also Known 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 for clarity purposes:

> !![]
// => true
> !!{}
// => true
> !!""
// => false
> !!undefined
// => false
> !!null
// => false
> !!0
// => false

This allows for a terser way to write if statements

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

Since troll is coerced to a boolean type, having the troll variable holding an object value will evaluate to truthy and having it holding null or undefined will be falsey. In either case the if statement will fulfill its purpose while being much nicer to read.

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):

// 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):

// 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:

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

> 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 (/):

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

Or by creating a RegExp object:

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

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

> 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 these issues when building real web applications 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.

Concluding

And that was a summary of pretty much the whole JavaScript language. I really hope it has sparkled your interest for JavaScript and that you cannot wait to turn the next page and learn more. But first, let’s make a quick review of what you’ve learned in this chapter.

We’ve seen that JavaScript is a very flexible dynamic language that supports many paradigms of programming and has a lot of great features.

You have learned the many things you can do with strings and ES6 string templates. How functions are very independent entities that can live their own lives completely separate from objects and how they are a fundamental building block of applications in JavaScript. You also discovered arrow functions that resemble lambdas in C# and let you write super terse and beautiful code.

We took a look at objects, object initializers, prototypical inheritance and ES6 classes. We saw the different data structures supported, the versatility of the array and an overview of the new ES6 Map and Set.

We also examined more general language features like the flow control structures and logical operators. We saw the difference between abstract comparison and strict comparison, 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 exception handling and regular expressions, and we saw some of the weird and best-avoided behaviors in JavaScript.

/*

The first rays of a new day like dubious trendils of light 
start approaching the clearing when Randalf notices that the 
stranger is looking weirdly at him...

*/

randalf.says("Yes, I know what you are thinking, " + 
             " it is a lot to take in...");
stranger.says('...err... no... Who the hell are you? ' + 
              'and whaaaat is a kender?!');
  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. For those of you not familiar with magic, mana can be seen as a measure of magical stamina. As such, doing magic (like summoning minions) spends one’s mana. An empty reservoir of mana means no spellcasting just as a empty reserve of stamina means no more running. 

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

  4. One does not simply change the prototype of an object willy-nilly at runtime since it can affect performance a lot. Instead, you would use Object.create or a function constructor, and if needed, you would augment the prototype as needed. 

  5. like a hobbit but with shoes. If curious look up the joyful, corageous and beloved Tasslehoff Burrfoot. 

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

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