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?
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…
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:
And I can do some alchemy thereafter and transform the minion into something else, a string, for example:
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:
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:
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…
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 ("
):
JavaScript also has a boolean type to represent true
and false
values:
And an object type that we can use to create any new custom types:
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.
This can get even more confusing because of the fact that there’s a third possibility. That a variable hasn’t been declared:
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.
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:
And so do strings:
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:
Then unwrap the original value with valueOf
:
Even more remarkable than numbers and strings, functions behave like objects. They have their own methods:
And you can even add properties to a function:
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.
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:
Any string has a number of useful methods:
ES6 also brings a number of new methods like startsWith
, endsWith
, repeat
:
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
:
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:
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
:
ES6 Template strings let you write a multi-line string in a more straightforward fashion:
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:
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:
And even with no arguments at all, although depending on the function implementation it may cause some chaos and some mayhem:
You can use the very special arguments
array-like object to get hold of the arguments being passed at runtime to a given function:
Or the finer ES6 rest syntax reminescent of C# params
:
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:
But that was a little bit awkward, what if we return a function with the new functionality that we desire:
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#:
But if we replace the if
block with a new function inner
, then we have two scopes:
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:
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.
ES6 Default Arguments
ES6 finally brings default arguments to JavaScript functions, and they work just like in C#:
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:
Even when passing an object to a function:
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:
And if you have a function with more arguments or statements, you can write it just like we do in C#:
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:
ES6 makes easier to create object literals with syntactic sugar for functions also known as method shorthand:
And for creating properties from existing variables also known as property shorthand:
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:
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:
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:
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).
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:
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:
ES6 exposes the __proto__
property that lets you directly assign a prototype through an object literal:
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:
And so does inheritance:
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 []
:
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:
You can access the items of an array via their indexes:
You can also traverse the indexes of an array using the for/in
loop:
And even better the items of an array using ES6 for/of
loop:
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:
And even LINQ-like methods to perform functional style transformations within an array:
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:
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:
You can even seed a map with existing information by sending an array of key/value pairs6:
In a similar fashion, you create sets using the Set
constructor:
Sets will ensure that you don’t have duplicated data within a collection:
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:
And the ES6 for/of
loop that lets you iterate over collections7 (arrays, maps and sets):
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:
Fortunately JavaScript also provides operators that performs strict equality ( ===
and !==
) which is basically a comparison of two values without the implicit type conversion.
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:
This allows for a terser way to write if
statements
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):
The AND operator will return the last truthy expression or the first falsey expression (if any falsey expression is encountered):
Exception Handling
Exception handling works similar as in C#, you have your familiar try/catch/finally
blocks:
And you can throw new exceptions with the throw
keyword:
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 (/
):
Or by creating a RegExp
object:
Strings have built-in support for regular expressions as well with the match
and search
methods:
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:
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.
-
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. ↩
-
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. ↩
-
As an article of interest you can augment objects in C# if you use the
dynamic
keyword withExpandoObject
s ↩ -
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. ↩
-
like a hobbit but with shoes. If curious look up the joyful, corageous and beloved Tasslehoff Burrfoot. ↩
-
in reality, it does not need to be an array, but an iterable that produces key/value pairs
[<key>:<value>]
↩ -
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. ↩