This month’s column continues the discussion on JavaScript language features. For the last couple of months, the topic of dynamic languages such as JavaScript and how they differ from traditional statically compiled languages like C/C++ has been covered. In this column, the focus is on the functional nature of JavaScript.
In languages like C or C++, functions are associated with a specific piece of work that needs to be done. So we define functions, which take inputs in the form of arguments passed to them or through global variables, then operate on their inputs, either in terms of computations or performing I/O, and then return a result value to the caller. Typically, functions are invoked using the function name directly, or through a function pointer. Passing functions as arguments is not that common, except as function pointers in C, or as functor objects in the case of C++. A typical example of a function passed as an argument to another function is C’s qsort, which is the quick-sort implementation in the C Standard library. Here is its declaration:
void qsort(void *start, size_t num_elems, size_t elem_size, int (*my_comparator)(const void *, const void *));
In the above declaration, qsort takes four arguments; the last is a function, which does the comparison between two elements of the array to be sorted, and returns an integer, which is the result of the comparison. One would typically invoke qsort as below:
int my_comparator(const void* elem_ptr1, const void* elem_ptr2)
{
/* perform your comparison here */
}
int main(void)
{
Qsort(int_array, N, sizeof(int), my_comparator);
}
This is an example of what is known as a higher-order function one which either takes a function as an argument, or returns a function as its return value. A typical use-case for passing functions in operating systems code is as callback functions. This will be executed when a certain condition (such as the elapsing of a timer) is met. Functions that are not higher-order functions are known as first-order functions.
Now, you may ask why we are talking about higher-order functions. You will see these very frequently in JavaScript, so it would help to be familiar with them.
This pointer and scopes
Those of us who have programmed in C++ are familiar with the this pointer, which is a special type that points to the object of which a non-static member function is being invoked. Let X be a class, and my_A an object of class X. We have a member function in X named foo.
class X
{
int age;
int birthyear;
string my_name;
public:
void set_birthyear(int year) {
this->birthyear = year;
}
}
….
X my_A;
// equivalent to my_A.set_birthyear(&my_A, 1971)
my_A.set_birthyear(1971);
Consider the code snippet above. In the member function set_birthyear, we used this->birthyear to refer to the data member birthyear of the object on which the function set_birthyear is invoked. Note that we typically do not write this->birthyear, but just write the assignment as birthyear = year; since the usage of this is implicit. When you invoke my_A.set_birthyear(1971), it is as if you have written the invocation as my_A.set_birthyear(&my_A, 1971). The first argument is the this pointer, which is the pointer to the receiver object on which the function is invoked. Note that we cannot explicitly declare the this pointer, nor can we assign a different object to the this pointer in C++. It is not possible for me to pass a my_B object address as the this pointer in the above call, to set_birthyear. However, this behaves differently in JavaScript, and it would be useful to understand the difference. Before we discuss this, let us briefly explore scopes.
In C or C++, you can create a new scope by block statements. Whenever you open a new curly brace, it creates a new scope. For example, consider the following code:
int my_var = 1;
int main(void) {
int my_var = 10;
/* start a new scope here by a block */
{
int my_var = 20;
int your_var = 30;
//This prints 20 and 30
printf(%d is my_var and %d is your_var \n, my_var, your_var);
}
print(%d is my_var, my_var); //This prints 10
/* this will give a compile time error saying undefined variable
printf(%d is your_var, your_var); */;
}
In the above code snippet, there is a global named my_var. Inside the main function, we defined a function local called my_var, whose definition hides the global my_var definition. We then started a new block scope, and defined a block local variable my_var. The scope of the block-local variable is just the block where it is defined. Therefore, when we print the value of my_var, outside the block and inside main, we get the value of my_var as 10. The function-local my_var has the main function as its scope. On the other hand, in JavaScript, the only way of creating a scope is by means of functions. You can’t use block statements represented by curly braces, or for loops, or anything else to create a new scope. The variables in JavaScript follow lexical scoping, which means that their scope is determined by the physical position of their definition in the source code not by where the function is being called from.
Now let us get back to this in JavaScript. It refers to the current context, which is basically the receiver object of the method being invoked. Consider this JavaScript code snippet:
var Employee = {
name: Sandya,
joinyear:2012,
age:40,
salutation: function () {
return Hi + this.name + You joined in + this.joinyear;
}
};
Employee.salutation();
In the above code snippet, we defined a JavaScript object Employee and invoked the salutation function of that object. Inside the salutation function, we used the this context to refer to the receiver object (Employee, in this case). This is very similar to the behaviour you would see with C++. Now consider the following code snippet:
var bad_call = Employee.salutation();
bad_call();
Now the output is Hi undefined You joined in undefined. Basically, the fields this.name and this.joinyear are now undefined. Why does this happen? In the above code snippet, when we invoked bad_call, the this does not point to Employee. Instead, it points to the global object and not the Employee object. The fields name and joinyear are undefined in the global object, and hence you get the output for their values as undefined. Therefore, in JavaScript, the context pointed to by this changes, depending on how a function is called. Let us next take a quick look at closures.
Closures in JavaScript
function greet(){
var name = sandya;
function greet_by_name() {
alert (hello + name);
}
greet_by_name();
}
In the above code snippet, there is an inner function greet_by_name, which is defined inside an outer function greet. The variable name inside the inner function will match the variable name defined in the closest enclosing scope which, in this case, is the variable name defined in the outer function, greet. Therefore, we can print the name as sandya in the inner function greet_by_name. Now let us consider a slight modification to the above code:
function greet(){
var name = sandya;
return function greet_by_name() {
alert (hello + name);
};
}
//This is where the closure is created
var greet_sandya = greet();
//the closure function is invoked
greet_sandya();
If you run the above code, you will see the same output as before. However, note that we returned a function greet_by_name from the function greet. So when we executed the statement var greet_sandya = greet();, we only executed greet, and assigned the return value greet_by_name to the variable greet_sandya. We did not actually execute the function greet_by_name.
When we executed greet_sandya in the next line, we executed greet_by_name, since it had been assigned to the greet_sandya variable earlier. Now, the question is: How is greet_sandya able to access the variable name defined inside its outer function greet successfully, even though greet has already finished executing? Well, the answer lies in closures. A closure not only includes a function definition, but it also includes the environment where the function was defined. This allows greet_sandya to access the variables defined inside greet when it is actually executed. However, it is not all that simple. Since name is a local variable allocated on the stack of the greet function, how can it still be available when the function greet has already finished execution and is no longer active on the call stack? Well, that will be answered when we discuss closures in detail next month.
My must-read book for this month
This month’s must-read book recommendation comes from me, and it is for a book titled Cracking the Systems Software Interview, published by TMH, and co-authored by Ganesh (author of the Joy of Programming column) and me. This book was in response to the requests by many of our readers for a quick refresher to prepare for systems software interviews in product companies. It covers coding questions, algorithms, operating systems, computer architecture and concurrency. It is based on our experience of conducting interviews in product MNCs over the last 10 years. Please do let me know your comments and suggestions to improve the book.
If you have a favourite programming book or article that you think is a must-read for every programmer, please do send me a note with the book’s name, and a short write-up on why you think it is useful so I can mention it in this column. This would help many readers who want to improve their coding skills.
If you have any favourite programming puzzles that you would like to discuss on this forum, please send them to me, along with your solutions and feedback, at sandyasm_AT_yahoo_DOT_com. Till we meet again next month, happy programming, and here’s wishing you the very best!