Introduction
Coming to JavaScript from C#, I came across some new terminology, as you would expect. Here I'll run through some of those new terms, with some examples of what exactly they're about. Some of them aren't really "new" terms, but have different or special meanings, and that warrants their inclusion here.
Contents
Anonymous
Anonymous functions are those with no name.
As I've said before, the ECMAScript specification does not have any mention of the term anonymous, so in a sense it is open to interpretation. However, there is a clear consensus from the JavaScript community on the "no name" definition - with sources including Crockford, Mozilla, the Chrome debugger and Firebug.
So, for the avoidance of doubt, this is an anonymous function. It is assigned to variable func
, and so forms a "function expression":
var func = function(){
...
};
In this next case, the function is not anonymous because it has a name. Also, because it isn't assigned to a variable it forms a "function declaration":
function func(){
...
}
Now, both of these options will result in a function being defined, and available via an identifier named 'func
'. So in both cases, we can call it normally:
func();
In practical terms, what is the effect of an anonymous function? The answer is: brevity, and that's it. You should normally give each function a name to ensure that during debugging, you can see its name in the call stack.
Closure
Closures are a central concept of JavaScript and should be one of the first things that a JavaScript programmer learns. They can be very powerful and will allow us to emulate many patterns from other programming languages.
A closure is a functional scope (a set of variables) which is kept alive after the function returns.
To put that another way, through the cunning use of an inner function, we can keep a reference to the variables in its outer function - even after the outer function returns. So, a quick example:
function outerFunc(){
var name = "bob";
return function innerFunc(){
alert("hello " + name);
};
}
var test = outerFunc();
test();
Now, here we have a more practical example. JavaScript doesn't have private
variables. However, we can create the concept of privacy by embedding private
variables in a closure - and only functions inside the closure will have access to them. This is how it works:
function carFactory(make, model) {
var count = 0;
function isBatteryDead() {
return true;
}
return {
make: make,
model: model,
start: function start(){
if(!isBatteryDead()) {
count++;
}
}
};
}
var fordFiesta = carFactory('ford', 'fiesta');
fordFiesta.start();
This is a powerful way to create private
members, but unfortunately the downside is that each time the carFactory
is used to create a car, a brand new copy of the member functions is created - instead of re-using the functions as we would be used to in C#. We can do that, however, using prototypes, explained later.
Note that returning the inner function isn't the only way to create a closure; all we need to do is to keep the scope alive after the outer function returns. Here are some more ways that can happen.
Example 1 - with setTimeout
function outerFunc(){
var name = "bob";
setTimeout(function(){
alert(name);
}, 0);
}
outerFunc();
alert("hello");
The output of the code above is an alert of "hello
" followed by an alert of "bob
". So even after the outerFunc
exits, we see an alert of a variable inside it.
Example 2 - assigning to an outer scope
var ref;
function outerFunc(){
var name = "bob";
ref = function innerFunc(){
alert(name);
};
}
outerFunc();
ref();
This one might look a bit complicated, but it's not really. We are simply creating a variable called 'ref
' which will reference the inner function. When the outer function executes, it assigns the inner function to that 'ref
' variable, then returns. Then we can look at our 'ref
' variable to access the inner function, along with the variables in its scope.
Currying
Currying is a technique whereby a function with multiple arguments is converted to a function with fewer arguments. You would do this in a situation where you already know the value of one or more of the arguments, and you'd like to get a function that only takes the arguments you don't already know - so you don't have to continually keep passing in the same arguments when calling it. This is made easy in JavaScript with its functions being first-class citizens that can be simply passed around at will.
Let's assume we've got a normal function that takes a number of arguments, such as this jQuery function that sets an attribute:
function attr(key, value) {
}
jQuery("#bob").attr("title", "this is the title");
Currying would involve doing the following, which is to wrap the attr
function in a new function with fewer arguments, and allows us to fix the values of two of the arguments (the jQuery object and the name of the attribute)
function getAttrFn(elem, key) {
return function(value){
elem.attr(key, value);
};
}
The above getAttrFn
works because we create a closure in which the element and key is stored until the returned function is executed. It is used like this:
var setTitle = getAttrFn(jQuery("#bob"), "title");
setTitle("this is the title");
One use of this technique would be to create an event handler function that matches the signature required, while passing other useful parameters to an existing function.
One downside, however, is that if used very frequently then a performance hit might be noticed - we are, after all, adding an extra function call to the stack each time we curry.
Hoisting
Variable Hoisting
Hoisting is when the JavaScript runtime does wacky things with your variables, by effectively moving the line on which they are declared. This helps to explain why (and how) there is no block scope, only function scope - because the variable declaration is "hoisted" up to the beginning of the function.
So, for example, we can observe the following phenomenon:
1. var a = 1;
2. function hello() {
3. alert(a);
4. var a = 2;
5. alert(a);
6. }
In this example, the variables defined within function "hello
" are defined at the top of the function, i.e., line 3. The interpreter in essence executes this code:
1. var a = 1;
2. function hello() {
3. var a = undefined;
3. alert(a);
4. a = 2;
5. alert(a);
6. }
The variable a is hoisted to the top of the function. This is why in JavaScript, we should always try to declare variables at the start of the function so that this behaviour becomes obvious. JSLint enforces this.
Here is one other example which is also a little confusing, a for
loop:
function hello() {
for (var i=0; i<10; i++) {
}
alert(i);
}
This occurs for the same reason, that variable i
is hoisted to the top of the function instead of being scoped only within the for
loop.
Functional Hoisting
The hoisting of functions is similar, but not the same since there is a small distinction between function expressions and function declarations. Function expressions follow the same hoisting rules as variables:
expression();
var expression = function() {
console.log("hello");
};
...while function declarations are fully hoisted to the top - in other words, they are available right from the beginning of their outer function.
declaration();
function declaration() {
console.log("hello");
}
Type Coercion
Type coercion is the conversion of one data type to another. This should normally be avoided in JavaScript (double-equals forces type coercion, leading to strange effects; triple-equals does not perform any conversion and so is type-safe - this is much simpler and easy to understand).
The exception to this generalisation is when coercing to a Boolean
. This is because any value in JavaScript is either 'falsy' or 'truthy' - meaning it can be coerced to a boolean to use as a conditional in an if
statement, for example. Here are a list of the truthy values - everything else is falsy:
- True
- Numbers not equal to 0
- Non-empty strings
- Objects (even those without any properties)
- Functions
You can test whether a variable is truthy or falsy in the debugger by using !!
, e.g.:
var a = 0;
console.log(!!a);
The innermost exclamation mark coerces the value to a Boolean and gets its opposite. The outermost exclamation mark then reverses that.
Alternatively, you can more explicitly convert to a Boolean:
var a = 0;
console.log(Boolean(a));
Scope
Scope is in this article because scope is always functional. There is no separate block scope for loops of any kind, if
statements, etc. Wherever a variable is declared, its declaration (but not assignment) is hoisted to the top of its function. However, due to the existence of closures, the scope is not necessarily the innermost function. For further explanation, go back to Closure and Hoisting!
If you wish to create a separate scope, you can create a self-executing function.
A self-executing function is one that is both defined and called all at once. This is useful when you want to create a "block scope" - variables defined in it are not available outside it. Also, due to closure, it can see variables defined outside - the same as a block scope in other languages.
(function(){
var x = "hello";
}());
console.log(x);
This
In C# (and most object oriented languages), this
refers to the current object. However in JavaScript, this
refers simply to the object on which a function has been invoked. If the function isn't invoked on any object, then this
refers to the window object (which is perfectly natural - after all, functions are first-class objects themselves and don't require an 'owner' object).
Example 1 - global scope
function whatIsThis(){
console.log(this);
}
whatIsThis();
Example 2 - function declared as an object property
var obj = {
whatIsThis: function(){
console.log(this);
}
};
obj.whatIsThis();
Example 3 - invoke a function on an arbitrary object
var obj = { };
function whatIsThis(){
console.log(this);
}
whatIsThis.call(obj);
Prototype
JavaScript is a classless object oriented language. But if it's classless, then how do we define what objects should look like? The answer is prototypes. A prototype is an object that is assigned to the 'prototype
' property of a function. Then that function can be used as a constructor, and the prototype becomes a model of how the resulting object will behave.
var Vehicle = function () {
...
};
Vehicle.prototype = {
started: false,
start: function(){
}
};
var c = new Vehicle();
Use of the new
operator before a function call does a number of things:
- An new, empty object is created
- The new object is pointed towards the prototype
- The function is executed with the object as its context ('
this
' points to it) - The object is returned
Additionally, an inheritance pattern can be created by copying the "base
" prototype to the "super
" object.
For example, let's say Vehicle
is the base type (I'm working hard to avoid using the word class!) and Car
should inherit from it, we assign an instance of Vehicle
to Car
's prototype:
var Car = function(){
...
};
Car.prototype = new Vehicle();
Now that we've got the Car
set up, we can extend it by adding some additional functions to its prototype:
Car.prototype.OpenSunroof = function() { ... };
There are many, many ways to implement classical inheritance in JavaScript, but this technique of prototypical inheritance should illustrate how prototypes are used.