JavaScript Functions

Are you a developer who adamantly hates JavaScript and would give up your firstborn before taking on a project that involves said language? If so, you are not alone. JavaScript seems to be one of those languages that polarizes us into two groups:

TEAM SIMBA

Members of this group believe JS is the rightful king of the web (and possibly server). They believe JS is easy and fun to develop with and mature enough to handle anything you throw at it. They praise the language for its impressive developer community and rich ecosystem of libraries.

TEAM SCAR

Members of this group believe JS is a twisted and deceitful language. They are obstinate that JS is a broken language flawed from its conception and mired by designers and the 90s. They see the language and its associated tooling as too “immature” for any real work. Of course, all JS libraries are just the hyena minions sent upon the web (and now server) to ravage and uglify the beautiful landscape that computer scientists have diligently built over the past six decades.

I believe both groups have valid points. JS can be a bit idiosyncratic at times. I have been burned a few times by many of the questionable “features” of the language. For example, double-equals is not equivalent to == present in many C-style languages:

if ("" == 0) //this statement is true...
	console.log("Seriously?!")

The above code snippet is known to make minds explode!

If you are like me, you probably learned C or some language based/inspired by it. The reason behind the behavior above is that == actually is an equality operand that performs type-coercion first. But there are also some very neat things going on in JS, and perhaps the best attribute is function-passing. There is great power in the ability to pass functions as arguments — just ask any Scala programmer! While functions are fundamental to JS, they are a topic that confuses a lot of developers, so let’s get started.

Functions

As you may have heard by now, functions in JS are first-class citizens. This means that the language allows functions to be assigned to variables or any other data structure, passed around as arguments to other functions, and returned from functions. Functions can be either a pure function or a non-pure function. Pure functions are equivalent to those in mathematics, they return the same outputs for the same inputs. Non-pure functions are those that produce side-effects. These types of functions are not required to return a value (when you do not explicitly return a value, the function will return undefined). Let’s take a look at how functions are defined:

function abs (number) {
    if (number < 0)
		return -number;

	return number;
}

var concat = function (str1, str2, seperator) {
	var s = seperator = seperator || " ";

	return (str1 + s + " " + str2);
}

var character = {
	name: "Simba",
	sayHello: function () {
		console.log("Hello, I'm " + this.name  + " and I just can't wait to be king!");
	},
	pounce: function (pouncee) {
		console.log(this.name + " has pounced on " + pouncee);
	}
}

Function declarations take on the form:

function optional_name ([optional_argument(s)]) { //function body }

Function expressions take on the form:

var some_name = function ([optional_arguments]) { //function body };

Knowing the difference between function declarations and expressions is important. A function expression differs from a declaration in that the function is assigned to a variable. Each type of function has some unique attributes that you must account for when doing any JS development. Other than the main difference between function types, all functions require { } around the function body and ( ) to succeed the function keyword and optional function name.

Functions can also be anonymous – a function without a name. Having a function without a name can be extremely convenient. Imagine having to have a name for the most trivial of functions or for defining a callback method. Let’s look at the character object again:

var character = {
      name: "Simba",
      sayHello: function () {
            console.log("Hello, I'm " + this.name  + " and I just can't wait to be king!");
      },
      pounce: function (pouncee) {
            console.log(this.name + " has pounced on " + pouncee);
      }
 }

Notice the anonymous function assigned to pounce? In this context, would it really add more value to rewrite that anonymous function as a named function?

...
    pounce: function pounce(pouncee) {
            console.log(this.name + " has pounced on " + pouncee);
      }
...

Doing this will not make the function pounce available outside to the global object since it is a function expression. We will discuss scope at a later point in this series. There is also the matter of defining a callback:

function strike (victim, done) {
    console.log("Getting striking arm ready...");

    done(victim)
}

strike("Simba", function (victim) {
    console.log("Rafiki has struck " + victim + "!!!");
})

In this example, you can see there is not much point in specifying a name for the function being passed into the strike; function. Sure this example is a bit contrived and not very useful, but at least it shows some instances where naming a function takes more effort than benefits gained.

Invoking Function

So far, I have only discussed defining functions. But what’s the use of a bunch of function definitions if they aren’t being used? I want to take a moment to talk about calling functions. Unless you’ve been living under Pride Rock (yes, another Lion King reference!) you have undoubtedly seen how to invoke functions. But I will explain, again, just for completeness… The most common way to call your precious functions is to simply write function_name(). See, it’s so easy, even Ed can do it!

Poor Ed, a victim of another shameless reference

Now JS wouldn’t be too interesting if there was only one way to call a function! Most of the confusion fun involved with JS are the many ways to do the same thing. According to Douglas Crockford, aka the JS Guru, there are four ways to call JS functions. The method mentioned previously is the function form. If you have were paying attention to my code examples, you will have noticed I defined a function as part of my object character.

var character = {
      name: "Simba",
      sayHello: function () {
            console.log("Hello, I'm " + this.name  + " and I just can't wait to be king!");
      },
      pounce: function (pouncee) {
            console.log(this.name + " has pounced on " + pouncee);
      }
}

character.pounce(“Zazu”);
character[‘pounce’]("Zazu");

In this form, the function is known as a method and calling it is known as the method form. Notice that we can also call this function by specifying the name of the function inside [ ].

There are two other forms that I did not use in my examples. The constructor form and the apply/call form. The constructor form is identified by the use of the new keyword.
var func = new Function([optional_arguments], functionBody)

var abs = new Function(['number'], 'if (number < 0) return -number; return number;');

console.log(abs(-8));

What this form should show you is that all functions are objects! All new functions created inherit the properties and methods of Function.protoype  — this type of inheritance is known as prototypal inheritance. Although invoking these types of functions looks exactly like the function form, there are some characteristics of calling this form that differ from the function form, these will be covered later in this series.

The apply/call form is particularly important as I believe it can help you to understand the internal [[call]] method that all functions have. The apply/call form is just a very small abstraction around [[call]] thus, understanding this form ensures you understand what’s going on behind the scenes of all the other forms. Just look at all the other forms as syntactic sugar for this form.

Annotated ES5 Specification 15.3.4.4 | The Function's call method

According to the ECMAScript 5 spec, a functions call method takes two optional parameters: thisArg and 0, 1, …, n arguments. The important thing to note about this is that the this keyword is set to thisArg, in other words, this is explicitly set in this form. Think about that for a moment…

Remember I said to think of all other forms of invoking a function as de-sugaring to this? Let’s go through some examples to see what I mean:

character.pounce("Nala");	//Simba has pounced on Nala
character.pounce.call(character, "Nala");	//Simba has pounced on Nala

console.log(concat("Houston", "Texas", ","));	//Houston, Texas
console.log(concat.call(null, "Houston", "Texas", ","));	//Houston, Texas

console.log(abs(-16));	//16
console.log(abs.call(null, -16));	//16

All of these return/output the same result. The only difference between the call and non-call methods is the explicit setting of this, I will not be focusing on the this keyword and its value in the part, that will be covered when I discuss scope. The apply method is very similar to the call method. The difference lies in how the arguments to the method are passed: apply takes its arguments as an array.

var numbers = [6, 4, 87, 52, 5, 21];

function sum () {
	var result = 0;
	var i;

	for (i = 1; i &lt; arguments.length; i++) {
		result += arguments[i];
	}
	return result
}

console.log(sum(6, 4, 87, 52, 5, 21));    //169
console.log(sum.apply(null, numbers));    //169

That is my brain dump on functions for now. I hope it made a bit of sense and you took away something of value. I will be discussing scope in another post and I promise I will try to make it somewhat bearable! For now, you can go create and call functions like a baus!

About William Shepherd

William Shepherd joined AIS in 2012 after graduating from Trinity University with a B.S. in computer science. William is part of the San Antonio office and works as a software engineer. He has been working with ASP.NET and other web technologies for two years and is currently learning SharePoint.