Skip to content
bebraw edited this page Apr 13, 2013 · 10 revisions

So far we haven't seen much code apart from that one line. Instead of boring you even more with yadda yadda, let's dig into some brief examples. I won't go through the whole specification. I will rather cover some features that are 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 imperative style 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.

Globals

Next I'll show you how to leak globals. Consider the example below. Can you see what changed? Why is the example leaking?

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

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

    return ret;
}

Even though the change was quite innocent now we have a leak in our hands. len is polluting our global namespace. All we did was to forget to declare our len as a var.

Many consider this a design flaw of JavaScript and I would agree. It is a good idea to declare which variables you are going to use at the beginning of the function. There are various opinions on how to achieve this syntactically but the above (apart from the bug) is what I like to stick with.

In browser environment the global namespace is also known as window for some curious reason. As this might not be the case in other environments I'm using the more general term here. This is also why it is not that nice to depend on window.

Partial Application

Let's say we have a bunch of forenames (say ['Joe', 'Jack', 'Jill']). For a sake of example we will want to suffix those with a surname. As we are being really original here, let's pick 'Johnson' as that isn't generic at all. How could we achieve that using JavaScript? You can go and code something now. I'll wait here for a while.

I hope you have something together now. Even if you don't, let's consider the problem a while. This sounds like a map. So it must be a map. Now how to define that. We'll, just look above. You can find the definition there. In case we are feeling particularly lazy and happen to have the right browser at our disposal, the snippet below will do the trick:

['Joe', 'Jack', 'Jill'].map(function(n) {return n + ' Johnson';});

Yeah, that's simple but not very over-engineered yet. How can we make our intent clearer? What if we wanted to apply the same function to some other list of items? As this is a contrived example anyway, let's try some partial application.

partial application is a way to specialize functions. In case you know how Object Oriented Programming and inheritance works in principle, you can consider this an analog to inheritance. We are simply taking something generic and making it more specific.

Instead of map I will want to end up with johnsonMap in this case. It will take a list of names and return a list of johnsoned names. Simple as that. As it happens ES4 provided us the perfect function for this purpose. It is also known as bind. There are shims available for less fortunate browsers.

The way it works is very simple. As you might guess from its name, it binds the values of function arguments to those given. In our case we can end up with something like this given we use the map definition above. This should explain why I prefer to have that callback argument as the first.

var johnsonMap = map.bind(undefined, function(n) {return n + ' Johnson';});

johnsonMap(['Joe', 'Jack', 'Jill']); // should yield the same as above

What's up with that first parameter? This brings us one of the perhaps confusing aspects of JavaScript. This concept is also known as this. Confused yet?

Sometimes you might want to bind console.log. Perhaps a bit counterintuitively just console.log.bind(undefined, 'prefix: ') won't work. Instead you will need to provide console as context like this: console.log.bind(console, 'prefix: ').

What is this?

this refers to function context. What is this context then? It depends. In this case we may set it explicitly. This means we may access contents of this Object within the context itself.

As I fear I may have confused you even more with this explanation, let's consider something more concrete. If you are as unlucky not to know what an Object is, let's stick an Object to our example. In computer science terms JavaScript Object can be considered a map of key-value pairs. All keys are always Strings whereas values can be pretty much anything.

var obj = {
    ctx: function() {console.log(this)},
    name: 'demo object'
};

obj.ctx(); // -> ???

Can you guess what object.ctx() prints out? That's right. We should see the Object itself there. Handy isn't it?

this can actually be fairly dangerous at times. It is a good idea to think through whether or not you really need it. Some libraries, such as jQuery, tend to rely on it somewhat. I don't consider that good design personally as you are effectively trading off some composability. And the last thing I want to do is to call certain functions using either call or apply speaking of which that is probably what I should cover next.

Understanding call and apply

These two might remind you of that beautiful bind. As it happens these three are siblings. call is the ugly one and I tend to favor apply over it. These two functions allow you to... wait for it... call functions. What's the point you might ask?

Suppose you are writing a test runner. You might have some kind of a function definition for the tests. It could be an Object containing name, test function pairs for instance. You will need some way to run them. This is where these guys I just introduced you to come in.

The difference between the nice apply and the less nice call is that the former accepts the parameters within an array while the latter just accepts them. It reminds me of bind this way. Both take a context parameter first and then do their thing after.

As I don't feel like writing an entire test runner here, I'll leave it as an exercise to the reader. Just to make everything clear, consider the following apply of console.log.

console.log.apply(console, ['you da js champ!']);

You can probably guess what happens there. If not, it's still not too late to change the career.

Arguments Are Fun

It is definitely fun to argue. Oh wait, I was supposed to introduce you to arguments. Not arguing with people. Wrong book.

There are generally put three ways to deal with function parameters in JavaScript. And no, I won't have an argument with you over is it a parameter of an argument. If you look from the outside, it's a parameter. If from the inside, it's an argument. Capiche?

The first way is the one we have used a lot already. You simply pass the parameters in a specific order and the function gets those as arguments in that specific order. Nothing complicated there.

Unfortunately JavaScript doesn't provide named parameters for us yet. As it happens it is possible to work around this problem with a little bit of Object magic. There is something about Object.

The third way has to do with the keyword arguments. You can probably guess what that contains. It looks like an Array but isn't quite like one.

As you might be mighty confused right now about what the guy is blabbering about, I've concocted amazing functions performing additions in various interesting and imaginative ways.

var add = function(a, b) {
    return a + b;
}

var addNamed = function(o) {
    return o.a + o.b;
}

var addMany = function() {
    var ret = 0;
    var i, len;

    for(i = 0, len = arguments.length; i < len; i++) {
        ret += arguments[i];
    }

    return ret;
}

I generally favor the first variant in my APIs. If the amount of parameters goes beyond three, I start to question myself even more than usually. That is usually a sign that something needs to change. I use the second variant particularly for jQuery plugins. In that case I often merge the passed parameters over some default ones using $.extend. The last one is preserved for special cases only.

Even though arguments might look like an Array, it isn't one. As MDN suggests, you can convert it to one either by using Array.prototype.slice.call(arguments) or Array.slice(arguments). You can shim latter in.

I hope this settles the argument once and for all. That Array.prototype actually looks a bit interesting. What's that about?

Prototypes Are Phun?

As I have mentioned earlier JavaScript does not implement classical inheritance scheme "as is". Rather it provides something known as a prototypal scheme. Each object points to some prototype object. It is possible that the object itself shadows some functionality provided by this prototype one.

It is possible to build more complex relations based on this simple scheme. For instance you could model the classical scheme quite easily. If this topic interests you, I recommend checking out Angus Croll's excellent post on the subject.

Back when jQuery was still in early stages there used to be another popular library known as Prototype. As you might infer from its name, it injects some functionality into prototypes of certain commonly used objects. This was also one of the reasons why jQuery surpassed it in popularity. In short mucking up with those is just asking for trouble as it might lead to breakage in interesting places.

Personally I don't use prototypes a lot these days and rather tend to avoid them. The "new" keyword is one reason. In my view it's just unnecessary syntactical clutter. In practice you see both styles prevalent. An example of "newless" style I prefer may be found at colorjoe, a color picker I have developed.

In colorjoe I provide a couple of specialized versions of the colorpicker: colorjoe.rgb and colorjoe.hsl. There is a also a chaining syntax and ways to extend the system without having to modify the core code. It is an example of how to use the factory pattern.

Factories and Generators

If you have used Java you have likely seen the joke about AbstractSingletonProxyFactoryBean. As it happens factories are actually an interesting way to construct specialized objects. JavaScript's closures enable us to create factories quite easily. This allows us to implement a pattern known as generator. In Python or some other language you might have bumped into yield keyword. That's what we're going to effectively implement next.

A generator is quite a simple thing really. It is just something that gives us a value when we poke it correctly. Let's get started with something very simple and generalize that later. The simplest possible generator I can think of generates just a series of same values (say 42). Here's an implementation of this particular case.

function numberGenerator() {
    return {
        next: function() {
            return 42;
        }
    };
}

var gen = numberGenerator();
console.log(gen.next(), gen.next()); // -> 42 42

As you can see we can get a nice series of 42's right now. That is only part of the story, though. We could parametrize the function as you might not want a 42 always. We could also take it a step further and make it use some rule. Let's say we want to get a series of n^2. Time to code!

function powerGenerator() {
    var i = 0;

    return {
        next: function() {
            var ret = Math.pow(i, 2);

            i++;

            return ret;
        }
    };
}

var gen = powerGenerator();
console.log(gen.next(), gen.next(), gen.next()); // -> 0 1 4

This example shows us the power of closures. As you can see, we store i at the outer scope of the object we actually operate on. It seems kind of trivial but it is one of those features of JavaScript it really pays off to understand as it allows us to implement all sorts of nifty little patterns such as this quite easily.

You can take the approach even further and generalize it. Since we might not want to operate on pow or squares always, we probably should define some sort of factory. I have done this below. As a bonus there's a cyclic one.

function generator(valueCb, initial) {
    return function() {
        var i = initial || 0;
 
        return {
            next: function() {
                var ret = valueCb(i);

                i++;
        
                return ret;
            }
        };
    }();
}

function cycle() {
    var items = arguments;
  
    return generator(function(i) {
        return items[i % items.length];
    });
}
 
function pows(n, initial) {
    return generator(function(i) {
        return Math.pow(i, n);
    }, initial);
}

var color = cycle('red', 'green', 'blue'); // red, green, blue, red, green, ...

var nums = pows(1); // 0, 1, 2, 3, ...
var squares = pows(2, 2); // 4, 9, ...
var cubes = pows(3); // 0, 1, 8, 27, 64, ...

I hope this example gave you some idea of the power of generators and factories. I know that especially the generator pattern isn't used a lot but at least it makes a perfect excuse of an example and helps you understand a bit about closures.

One problem of the approach has to do with the next method. It doesn't sit that well with existing iterators. You will likely need to implement some custom ones to deal with that. On the other hand the approach is lazy by definition. So no computation will be done unless you really mean it. Overall it is just one example of how to program into language rather than in language to quite McConnell of Code Complete fame.

Properties for Fun and Profit

In the good old world of Java we used to have getters and setters. And you can of course have those in JavaScript as well in case you really want to. Since I came by properties in Python I've considered them ugly. Properties are a bit like attributes except they may invoke some computation or be derived based on other attributes. Since that likely sounded very vague and confusing it's a good time to discuss a concrete example.

Since I'm in an overengineering mood, let's implement an area calculator in a form of Object. It will have three attributes: width, height and area. area is something that is derived based on width and height and will be read-only since I don't feel comfortable changing width and height as area changes.

As support for this sort of programming is still a bit sketchy in the world of JavaScript, let's "implement something ourselves as save some money while at it"(r). I think the interface for our mighty area object might look like this based on our specification:

var f = field({
    width: 5,
    height: 10
});

console.log(f.width(), f.height(), f.area()); // 5 10 50

f.width(10);

console.log(f.area()); // 100

I know having to use that extra ()'s is bit of a bore. But it is the price of this particular scheme. In case you feel like, go ahead and implement the specification. If it is still too much to handle, consider my implementation below:

function field(o) {
    o = o || {}; 
  
    var ret = {
        area: function() {
            return ret.width() * ret.height();
        }
    };
  
    property(ret, 'width', o.width || 0);
    property(ret, 'height', o.height || 0);
  
    return ret;
}

function property(o, name, val) {
    var prop = '_' + name;

    o[prop] = val;
  
    o[name] = function(v) {
        if(v) o[prop] = v;
        else return o[prop];
    };
}

var f = field({
    width: 5,
    height: 10
});

console.log(f.width(), f.height(), f.area()); // 5 10 50

f.width(10);

console.log(f.area()); // 100

This is one possible implementation out of many. You could for instance play around with this but as I mentioned earlier this isn't something I don't particularly personally like since it adds some unnecessary complexity in code and it might bite you later. Anyway, do as you like. Sometimes you just cannot avoid this.

Data Types

JavaScript's basic types include Object, Array, String, Number, Boolean, null and undefined. Those probably sound pretty familiar to you. Object is a key-value map as you probably have figured out by now. Array is a zero-indexed ... well, array. Rather than having separate types for integers and floats, we get around with Number type in JavaScript. No need to make things more complex than that. Boolean is just that, true or false. null is a bit of useless one. It is a value that is known to exist but value of which is unknown. undefined is both and will be used as a placeholder in that var a; case for instance.

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.

This is yet another example of how to benefit from closures. There's that inner function (push), namespacing and all that shiz. Hopefully you have figured out how they work by now.

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.

Hoist the Sails!

So far we have seen various ways to deal with scoping in JavaScript. One very important fact to keep in mind is that the language use function level scope rather than block level one in which many programmers have gotten used to. Effectively this means variables declared within blocks might not behave as you would like. On the other hand JavaScript more than makes up for this with closures as we saw above.

There is one extra thing that you should be at least aware of: the concept of hoisting. Consider the example below:

function hoist() {
    console.log(a);
        
    var a = 42;
    
    console.log(a);
}

hoist();

Even though it might look a bit counter-intuitive, it gets interpreted just fine because of hoisting. a will get hoisted on top of the hoist function. It's value will be undefined initially, though, and the value will be assigned where it is assigned right now. Hoisting also applies to functions. This means you may declare them in an arbitrary order. I often like to declare my functions in some kind of a reading order (dependencies go usually below). This makes it easier and faster to scan through the code.

Ben Cherry has written an excellent post on the topic of hoisting. You should go and read it in case you are interested in the topic further. You will find some additional examples there.

Conclusion

I hope this chapter gave you some idea of the functionality JavaScript provides. I am certain I skipped a lot of it. This little subset I showed you here happens to be one I use quite actively. There are some other technologies in play as well but those will be covered later. In the next chapter I shall look into various Common Problems and how to deal with those.