Skip to content
bebraw edited this page Feb 3, 2013 · 21 revisions

This document is still very much in progress. In the meantime I recommend checking out JavaScript Garden and beginner's resources I've listed over at jswiki, the predecessor of jster.

The book(let) has been aimed for beginners and intermediate level programmers. If you feel that the content could be improved, do submit issues. I'll take those seriously.

JavaScript - a Misunderstood Language?

As you might know the first version of JavaScript was developed in mere two weeks at 1995 by a fellow named Brendan Eich over at Netscape Corporation. Initially the language was known as LiveScript but the marketing men decided JavaScript sounds more believable. After all it was the decade of Java. On retrospect it wasn't a good choice and a lot of confusion has ensued. Java is to JavaScript as ham is to hamster. Keep that in mind!

So how would you characterize JavaScript? Even though it looks a bit like Java or C due to bracing there it is actually an implementation of a couple of powerful languages in disguise. These languages are Scheme, a variant of Lisp, and Prototype. From former JavaScript inherited some of its functional programming capabilities whereas latter gave it prototypal inheritance system which in some ways can be considered superior to classical one used by languages such as Java.

Particularly JavaScript's functional capabilities make it in some ways an exceptional language. Prototypal inheritance has caused a lot of confusion but it is possible to get around that. In fact it is possible to implement a classical system using it.

Of course JavaScript comes with the usual imperative programming constructs (for, while, if, etc.) you might expect. There is also some legacy in form of Date and Math modules inherited from Java 1.0. There are some custom features even (with comes to mind) though it is better to avoid some of those.

In fact you can get a lot done by selecting a subset of the language and then using that to its full extent. As JavaScript can feel a bit unwieldy sometimes people have implemented languages that compile to JavaScript. These languages provide some constructs not found in the language and can for instance provide stricter typing.

altJS lists these languages. Have a look at a few of those. Keep in mind, however, that in order to get most out of the languages you are better off learning JavaScript well. It will definitely help when you are trying to decipher the code they generate.

Current State of JavaScript

Particularly in the last few years the usage of JavaScript has grown explosively. Instead of using it to sprinkle some functionality to their sites some people are using it to manage the whole stack from backend to frontend. This has been possible thanks to the increasing popularity of Node.js. A whole ecosystem has grown around it. Particularly NPM has been an important factor in this growth as it has allowed people to share their modules and use ones created by others.

Traditionally this has been a weakness of JavaScript as it does not come with de facto module system. I will get back into this topic later (TODO: link). Let's just say the situation is still a bit messy although it is getting better on the frontend side thanks to solutions such as RequireJS and browserify. The former implements a module definition known as AMD whereas the latter allows to use module semantics familiar from Node on the frontend side.

What makes JavaScript interesting is the fact that it is supported by a wide range of hardware already. Just imagine the mobile devices around that can execute it. And that is not counting all the desktop systems. It is as ubiquitous as a language can get. In some ways it can be considered the assembly language of the web generation. It is that important.

Even though it is widely supported it takes more than just a language to make something useful. That is where browser and server-side APIs come in. Sometimes the APIs aren't particularly easy to use. As the popularity of jQuery shows there is sometimes demand for solutions that make them easier.

During the last few years we've progressed a lot on the browser side. JavaScript engines have become more powerful. This trend was initiated by Google's Chrome and has since led to significant improvements in performance. Standards are supported better. Thanks to Microsoft and its initiatives with Internet Explorer 9 and 10 they've started to catch up with the others and in some ways gone past even. That is a good trend for us web developers as gradually we may start to ditch legacy solutions needed by antiquated browsers such as Internet Explorer 6.

If you have not hopped into the JavaScript train yet, it is a good time to do so now. It's not too late. In fact a lot of development is going on. Newest developments include the introduction of MVC frameworks on the frontend side and reactive programming. Particularly latter seems to be trending currently. There has also been development on the asynchronous side as solutions have been provided that allow us to deal with callbacks in better ways. These include promise and future based solutions. In a way reactive programming yields a solution for this problem too.

The language itself is headed towards a brighter future with ES6. The specification promises to bring forth improvements such as long awaited modules, several language constructs and overall just standard ways of doing things so we can avoid reinventing the wheel ourselves. In fact you can mimic some of the planned features already but obviously it won't look or feel as good. On example of this is generators. I'll discuss this particular case later (TODO: link).

JavaScript - Language Features

We've gotten quite far and I haven't shown any actual code yet. It's time to change that. I won't go through the whole specification. I will rather cover some features I cover essential to know and understand well.

Functions

Let's start with a simple math function that clamps given input based on given bounds. Here we go:

function clamp(a, min, max) {
    if(a < min) return min;
    if(a > max) return max;

    return a;
}

In this case I decided to use a good ol' if statement to deal with the logic. The same may be written using ternary operators perhaps familiar to some from C.

function clamp(a, min, max) {
    return a < min? min: a > max? max: a;
}

It's getting a bit convoluted alright, maybe it's not a good idea to nest those. Finally we can rewrite it using native min and max functions inherited from Java 1.0. You will find a bunch of these at Math module.

function clamp(a, min, max) {
    return Math.max(min, Math.min(max, a));
}

// we can invoke any of these three simply using
clamp(4, 10, 20); // yields 10 in this case

There are likely some other ways to achieve the same result. The purpose of these three was just to give some idea of the basic structures and show the basic function syntax.

In JavaScript functions are first class citizen unlike in perhaps some less dynamic languages. You can simply pass functions to functions. These are also known as callbacks. This type of programming is quite commonly used in event based programming.

Let's define a simple map function this way. map is something that takes a callback (operation) as input, applies that operation for each member of the given data structure and then returns the result. In this case I'll stick to arrays although it is possible to generalize this approach to work with objects too. A basic implementation could look like this:

function map(cb, arr) {
    var ret = [];

    for(var i = 0, len = arr.length; i < len; i++) {
        ret.push(cb(arr[i], i));
    }

    return ret;
}

map(function(v) {
    return v * 2;
}, [34, 2, 5]); // yields [68, 4, 10]

There are a couple of things going on here you should be aware of. Notice the loop syntax. It's quite ugly alright but it's fine to use it on lower level constructs like this.

Sometimes it may be beneficial to name the callback (function mul(v) would work in this case) to make it easier to debug the code. The debugger will be able to use this information and show the name at a stack trace.

There is actually a nice alternative for the ugly default syntax. It is know as Array.forEach. Check it out. See Array.map while at it.

Using these may require shims depending on which browsers you want to support but on the other hand they make language so much more fun to use it's usually worth it.

TBD: partial, arguments (object + defaults + {}), factories (prop example), this

Data Types

JavaScript's basic types include Object, Array, String, Number, Boolean, null and undefined. It is possible to mimic more complex types, such as queues and sets, quite easily using these. A queue of sort can be implemented using an array. We primarily need to make sure that it's length has been fixed to some predefined value. It's implementation could look like this for example:

function queue(len) {
    var ret = [];
  
    ret.push = function(a) {
        if(ret.length == len) ret.shift();
        return Array.prototype.push.apply(this, arguments);
    };
  
    return ret;
}

var a = queue(3);
a.push('cat');
a.push('dog');
a.push('chimp');
a.push('giraffe');
console.log(a); // should contain dog, chimp, giraffe now

Here we abuse the fact that even an array is an object in JavaScript. In this case we simply attach a custom version of push to our queue. It keeps track of the queuing logic. Otherwise the functionality provided by array is enough for our purposes. You could for instance pop to get and remove the last item or shift to do the same but for the first item.

One interesting aspect of this example is the usage of a closure. As you can see the inner function (push) accesses its parent. This is a very powerful feature. We can implement various patterns by utilizing it. Remember that inner functions may access the content of their parent but not vice versa. Closures can be treated as namespaces.

We can do something a bit similar with sets. In this case we benefit from the fact that all keys of an object are unique. That is essentially the definition of a set. The only limitation of this approach is that we may use only numbers or strings as keys. Often this is enough, though.

Functions Are Objects Too

To paraphrase Mitt Romney functions are objects too. This means you may attach custom properties to them. These properties in turn may be used to do plenty of cool stuff. TODO: show how annotate.js does this.

Hoist the Sails!

TBD

Prototypes

TBD

Generators Revisited

Generator example.

Common Problems

TBD

Variables Are Global By Default

TBD. Explain global scope (window object in browser).

Function Syntax Is Cumbersome

TBD. Other languages, macros using sweet.js? ES6

Pyramid of Doom

Promises, futures, rx, q.

Not All Things Are Equal

== (coerces) vs. === (does not coerce)

Not Invented Here

Hard to find libs. Use JSter and other services. NPM for Node. Link to modules (next topic)

Modules

No module system by default!

AMD

CommonJS

How Node differs from CommonJS?

ES6

TBD

Transpiling

TBD

Package Managers

Frontend

Bower (component.json), Volo (AMD) and such.

Backend

NPM

Build Systems

Benefits: improved dev env (LiveReload and others, precompilers (CSS + languages that compile to JS))

grunt

jake

make

old skool

Boilerplates

TBD

Yeoman

TBD

Full Stack Using JavaScript

TBD

Frontend

jQuery, Backbone etc.

Backend

Node

Missing Topics

The Reddit thread contains some of the topics I should go through too.