The Basic Ingredients of JavaScript-Mancy: An Introduction to JavaScript and ES 6 For C# Developers
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.
{% img center comic—rotated-right /images/javascriptmancy-book-front-version-001.png “JavaScriptMancy!” “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 metaprogramming.
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.
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:
> 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 mana of course):
> 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 augment it with new properties to my heart’s content:
As an article of interest you can augment objects in C# if you use the dynamic
keyword with ExpandoObject
s
> 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 of any respectable string letting you store string literals. Interestingly enough, JavaScript strings support both single ('
) and double quotes ('
):
> 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:
> 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
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.
> 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.
> 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).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!".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
:
> 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:
> 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
:
> "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:
> `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
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:
> 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()
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:
> 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`);
}
> obliterateMany('Rabid bunny', 'leprechaun', 'yeti')
// => Rabit bunny, leprechaun, yeti are obliterated into tiny ashes
Or the finer ES6 rest syntax reminescent of C# params
:
> function obliterateMany(...targets){
var targets = Array.from(arguments).join(', ');
console.log(`${targets} are obliterated into tiny ashes`);
}
> obliterateMany('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:
> 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(`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#:
> 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 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:
> 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;
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:
/*
> 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#:
> 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:
> 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:
> 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:
> 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 = () => 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:
> 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 may items, by setting the item
object as the prototype of the ironTwoHandedSword
(and any other specific items that you create afterwards).
> 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:
> 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:
> 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 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:
> 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
> var aKendersPoach = [
'jewel',
'3 stones',
1,
{name: 'Orb of Power},
function() { return 'trap!';}
];
You can access the items of an array via their indexes:
> aKendersPoach[0]
// => jewel
> aKendersPoach[4]()
// => trap!
You can traverse the indexes of an array using the for/in
loop:
> 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:
> 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:
> 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:
> 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:
> 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 pairspairs:
in reality, it does not need to be an array, but an iterable that produces key/value pairs [<key>:<value>]
> 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:
> 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 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:
> 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 collectionscollections (arrays, maps and sets):
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.
> 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:
> 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 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:
> !![]
// => 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)
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 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.
Have a great week ahead!! :)
More Articles In This Series
- Chapter 0: The Basic Ingredients of JavaScriptMancy
- Chapter 1: The Many a One JavaScript Quirks
- Functions
- Object Oriented Programming
- Basics
- ES6
- OOP
- Introduction to OOP in JavaScript for C# Developers
- Summoning Fundamentals: Introduction to OOP In JavaScript – Encapsulation
- Summoning Fundamentals: Introduction to OOP In JavaScript – Inheritance
- Summoning Fundamentals: Introduction to OOP In JavaScript – Polymorphism
- White Tower Summoning: Mimicking C# Classical Inheritance in Javascript
- White Tower Summoning Enhanced: The Marvels of ES6 Classes
- Black Tower Summoning: Object Composition with Mixins
- Safer JavaScript Composition With Traits and Traits.js
- JavaScript Ultra Flexible Object Oriented Programming with Stamps
- Object Oriented JavaScript for C# Programmers
- Tooling
- Data Structures
- Functional Programming
- And more stuff to be shaped out:
- Functional Programming with JavaScript
- Modules
- Asynchronous Programming
- The JavaScript Ecosystem
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.