Functions in Javascript - Javascript Week Off
JavaScript – A language of first-class functions
After a summer of working with a technology, I felt that its important that I try to really fine-tune the knowledge of the language which I have worked with almost exclusively. A language that previous to the summer, I looked on with apprehension, more with a feeling that its power was limited due to the fact that it lived primarily in the browser, and my lack of experience with the language on platforms such as NodeJS was non-existent apart from a hello world http server.
The problem with JavaScript and ultimately why so many people dismiss it as a bit part language is because they know it only from snippets such as:
var x = document.getElementById("form_one_id").val();
The reason why this looks so disgusting and unusable is because its usually crammed in a html file, amongst other markup.
Powerful
JavaScript is a powerful and versatile language, although so often its main use is manipulation of the DOM (which by the way is an awful structure), its better to look at the things it has to its advantage.
- In certain environments such as the web browser, the javascript execution model is based around handling events.
- You can write it in many ways, classical, functional or a mixture.
- It is ubiquitous, any computer which has a web browser has an JavaScript interpreter installed.
- Once you learn its quirks (and it has plenty) you can be very expressive and elegant in what you write
- With technologies such as Ryan Dahl’s NodeJs JavaScript is a rising technology
- Many new interfaces are putting JavaScript as first class citizens, Windows 8 and Gnome 3 both have JavaScript interfaces to their products.
Functions in first class
For this blog post, I hope to go into some of the basics of JavaScript functions, the things I write here are almost entirely inspired and researched from Douglas Crockford’s excellent video series on Javascript, which I recommend you watch now.
The first thing to notice about functions in javascript is that they are objects, they can be passed around the same as strings, integers or in fact any other type of object can. This is very powerful, consider the following code which is possible (and quite common in normal JavaScript code)
function doSomethingWhen(seconds, func) { var ms = seconds * 1000; setTimeout( func, ms); }; function sayHello() { console.log("Hello World"); }; doSomethingWhen(5, sayHello);
This bit of code here shows how a standard callback system can be set up, it loads in a function as the second argument (this is just the function it is not the result of the function and then sets a timeout for the set amount of seconds and executes the function after that. The setTimeout is a classic example of JavaScript’s non-blocking code execution, using the event loop it will wake up after the given seconds and execute the function while any code after will be executed in the mean time.
Concept of function scope vs block scope
In JavaScript, there is no concept of block scope, i.e loops such as for loops or if loops don’t get their own scope of variables. There is a concept of variable hoisting, any var declarations in a JavaScript function are hoisted to the top of a function, I’ll give you an example now of how this can affect a programmer used to block scope in other languages.
note: Less than must be replaced by the normal sign, but due to a error in posterous markdown I’ve had to do it this way. Apologies.
Taken from Crockford Lecture “function the ultimate”
function assure_positive(matrix, n) { for(var i=0;i less than n;i+=1){ var row = matrix[i]; for(var i=0;i less than row.length;i++) { console.log(i); if(row[i] less than 0) throw new SomeError("Ugh"); } } }
This function assumes that the block scope of the first for loop will preserve the i variable and another local i can be created in the nested for loop. In reality this function is interpreted as follows by javascript:
function assure_postive(matrix, n) { var row = undefined, i = undefined; for(i=0;i less than n;i+=1){ row = matrix[i]; for(i=0;i less than row.length;i++) { console.log(i); if(row[i] less than 0) throw new SomeError("Ugh"); } } }
From this we can see, that the I variables are both the same variable so running this function will lead to a function with indeterminable execution (most likely an infinite loop).
What parameters does each function receive
Each function gets with it the following
- arguments – this is an array like structure which holds the parameters provided by the function invocation.
- this – a pointer to the object which the function is referring to
arguments
An array like object ( be very careful with this ), that holds the functions arguments as passed by the function invocation. It is not a real array, and depending on the JavaScript standard which your interpreter adheres to, it may not have all the array prototypes or perhaps none of them.
- In ECMAScript 3, this array doesn’t have the array’s reduce and forEach methods which can come in handy
- In ECMAScript 5, these were added so that the arguments can be reduced like a normal array.
Its best to treat the array like a read only array, as functions such as splicing or rearranging can have adverse affects on the object and can do things that aren’t standard for an array object.
Note: In Node, it runs officially on ECMA 3, although many of the ECMA 5 functions are usable, this is more of a V8 issue I imagine but please look at this thread for more details
this
So the this parameter is quite a complex one, and is also one that causes a lot of pain in many javascript circles, not the parameter itself but more the implementation of it in ECMA 3. We will go into this more in another section of this post.
The this is the object which the function is working on. The this is pivotal to key inheritance in javascript as the this parameter allows a function to modify the object it is meant to be working on. Again there will be more examples of this in the next section.
Function Invocation
In JavaScript, there are four ways to call a function, 1. Calling the function name of an object 2. Calling the function 3. Using the new parameter 4. Using the apply form
Calling the function
Lets define a function sum which takes two parameters,
function sum(a, b) { return a + b; }
To call this simple function we do a normal function invocation as follows:
var result = sum(2,3);
Invoking a function using the new operator
Lets say we want a classical object oriented cat object, it needs a name and it needs a function which says its name.
function Cat( name ) { this.name = name; this.sayName = function() { console.log(this.name); } }
To create an instance of this Cat, we use the new operator, this creates a new instance of the function and sets the this parameter to that new instance, if no implicit return is found, it returns the this, creating a new Cat Object.
var cat = new Cat("rover");
The new variable will now be able to access the object Cat’s functions (sayName) as well as all the normal Object objects methods (these are default for every object)
Calling an objects function
Now leading on from that example we can get our cat to say its name.
cat.sayName();
the sayName function which is a part of the Cat Object is called using the classic dot notation seen in a lot of other languages.
Calling a function using apply and call
Javascript provides two functions which are called apply and call, these allow us to explicitly set the values of this and arguments.
lets define another sayName function outside the Cat creator function.
var sayName2 = function() { console.log(this.name); };
to call this function on our cat Rover, we do the following:
sayName2.apply(cat)
The arguments variable was left blank in this case as no arguments were required.
More to come
Hopefully, this short post on functions opens your eyes to a little of the magic that is held behind this language, and believe me we are only tipping the iceberg of possibilities here, we also have massive area’s such as closures, returning functions, arrays of functions, hashes of functions and a lot more.
I’m only learning, so if I’ve made a mistake in this post please let me know either in the comments section or by email richdel@gmail.com
