Javascript The Good Parts: Functions

Why , every fault’s condemn’d ere it done:
Mine were the very cipher of a function…
 — William Shakespeare

This series is a short handbook of the book JavaScript: The Good Parts by Douglas Crockford. One can use this series to strengthen basic their concepts.

Functions are used to specify behavior of objects, for code reuse, information hiding and composition.

As Objects

  • Functions are objects in javascript. They are linked to Function.prototype which itself is linked to Object.prototype.
  • Every function has 2 addition hidden properties: the functions context and its arguments.
  • As functions are objects, they can be used like any other value. They can be stored in variables, objects and arrays. Or passed as arguments to function. They even can have methods as objects.
  • The thing that is special about them is they can be invoked.

Function Literal

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

It has 4 parts:

  • Reserve word function
  • Optional function name if not present it’s called anonymous function
  • Set of parameters, wrapped in parenthesis. Thing is instead of being initialized to undefined they are initialized to the arguments supplied when function is invoked.
  • Fourth part is the set of statements wrapped in curly braces.

Invocation

The two additional hidden properties that every function get are: this and arguments. The value of this is determined by the invocation pattern. Thus, invocation patterns differ the way this is initialized.

Method invocation pattern

Functions which are present as object properties.

var student = {
count: 0;
addup: function(a){
this.count += a;
}
};
student.addup(1);
console.log(student.count); // 1

Here the binding of this is to the objects context, just can access object properties directly. This binding happens during invocation time.

Function invocation pattern

Functions which is not the property of an object.

var add = function(a,b){
return a + b ;
}
console.log(add(2,3)); // 5

Note, when a function is invoked with this pattern, this is bound to the Global Object. Thus, when an inner function is invoked, this would still be bound to the this variable of the outer function. Below is a workaround to this problem.

student.message = function(){
var that = this; // Workaround, by convention variable name is that
 var helper = function () {
console.log('Total students count: '+that.count);
};
 helper(); //Invoke helper function
};
student.message(); //Invoke the method

Constructor invocation pattern

Functions that are intended to be used with the new prefix are called constructors, and by convention, they are kept in variables with a capitalized name.

var F = function (s){
this.status = s;
};
F.prototype.get_status = function(){
return this.status;
};
var myF = new F("Hello World!");
console.log(myF.get_status()); //Hello World!

Thing is, if a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function’s prototype member, and this will be bound to that new object.

Apply invocation

Apply invocation can be used to invoke a function on other objects as it provides arguments to set the context (this) of the function and also to pass arguments.

var F = function (s){
this.status = s;
};
F.prototype.get_status = function(){
return this.status;
};
var myF = new F(“Hello World!”);
var myStatus = {
status:”FIFA 2016"
};
var status = myF.get_status.apply(myStatus); 
console.log(status); //FIFA 2016

Arguments

var f = function (a,b){
console.log(a);
console.log(b)
};
f();// undefined undefined
f(10);// 10 undefined
f(10,20);// 10 20
f(10,20,30,40);// 10 20

If number of parameter passed exceeds then one can access them via argument array.

var f = function(){
for(var i = 0; i< arguments.length;i++)
console.log(arguments[i]);
};
f(10,20,30,40); // 10 20 30 40

Return

A function always return a value. If the return value is not specified, then undefined is returned. But, if the function was invoked with the new prefix and the return value is not an object, then this (the new object) is returned instead.

Exceptions

var add = function (a, b) {
if (typeof a !== ‘number’ || typeof b !== ‘number’) {
throw {
name: ‘TypeError’,
message: ‘add needs numbers’
};
}
return a + b;
};
// Make a try_it function that calls the new add
// function incorrectly.
var try_it = function ( ) {
try {
add(“seven”);
} catch (e) {
console.log(e.name + ‘: ‘ + e.message);
}
};
try_it( );
  • Exceptions can be handled using try catch block.
  • Throw statement interrupts function execution, exception object containing a name property that identifies the type of exception. On the basis of name one can handle different exceptions differently by chaining catch blocks.

Augmenting Types

All the basic types in javascript can be augmented. For example, by augmenting Function.prototype, we can make a method available to all functions:

Function.prototype.method = function (name,function){
if(!this.prototype[name]){
this.prototype[name] = function
}
};
// Also checking if the property does not exist already in the chain

JavaScript lacks a method for trimming of string, below is a fix:

String.method(‘trim’, function ( ) {
return this.replace(/^\s+|\s+$/g, ‘’);
});
console.log(‘”’ + “ neat “.trim( ) + ‘”’);

Scope

Javascript provides function scope. That means that the parameters and variables defined in a function are not visible outside of the function, and that a variable defined anywhere within a function is visible everywhere within the function.

var foo = function ( ) {
var a = 3, b = 5;
var bar = function ( ) {
var b = 7, c = 11;
// At this point, a is 3, b is 7, and c is 11
a += b + c;
// At this point, a is 21, b is 7, and c is 11
};
// At this point, a is 3, b is 5, and c is not defined
bar( );
// At this point, a is 21, b is 5
};

Closure

Closure comes into play when inner functions has a longer lifetime than its outer function. It can be used to hide information from the outer world.

var f = function ( ) {
var value = 0;
return {
increment: function (inc) {
value += typeof inc === ‘number’ ? inc : 1;
},
getValue: function ( ) {
return value;
}
};
};
var myObject = f();

If you note myObject has the returned value, that is object containing two methods. But it does not have direct access to value.

var quo = function (status) {
return {
get_status: function ( ) {
return status;
}
}
};
};
// Make an instance of quo.
var myQuo = quo(“amazed”);
console.log(myQuo.get_status( ));

As get_status is defined within quo function it has access to status variable. But the myQuo object can not access status variable. This, technique of attaching get_status method to an object is better than previous technique(refer to constructor invocation pattern).

All this is possible because the function has access to the context in which it was created. This is called closure.

Cascade

The methods which return this instead of undefined, one can enable cascade.

getElement('myDiv').move(350,150).color('red').on('mouseup','stopDrag');

Curry

It’s a way to manipulate function arguments and thereby function values.

Function.method(‘curry’, function ( ) {
var slice = Array.prototype.slice;

args = slice.apply(arguments);
that = this;

return function ( ) {
return that.apply(null, args.concat(slice.apply(arguments)));
};
});
var add1 = add.curry(1); //add is defined above
console.log(add1(6)); // 7

Note: args.concat(slice.apply(arguments); there args contains curry’s arguments and arguments is add’s arguments. We are doing slice as arguments are array like but not array so they lack concat method.

Callbacks

For callbacks kindly refer to my another post: