Posts tagged with 'functions'

JavaScript for C# developers: calling functions and the ‘this’ variable

I can’t believe that I haven’t posted an article on how to call functions in JavaScript and what this gets set to for each of the various invocation patterns. It’s one of those things that catches people out periodically, so it’s well worth discussing at length.

Lego123There are four different ways to call or invoke a JavaScript function: method invocation, function invocation, constructor invocation, and apply invocation. Each of these invocation patterns results in this being set to a different object inside the function. In C#, there is never any doubt what this refers to: it’s the object (the instance) on which the method is called. Using this is entirely optional, unless you are trying to resolve some possible ambiguity in the code (say, a parameter to the instance method has the same name as a field of the instance: in this case, to refer to the field you would have to use this). Of course, for a static method rather than an instance method, using this is an error and will be caught at compile-time.

Method invocation

Back to JavaScript. We’ll first talk about the equivalent to C#’s calling of an instance method: method invocation. This is just like the C# case: you’ve got some object and you call a method of that object. The this variable inside the function will be set to point to the object you’re calling the method on. In essence, pretty much exactly the same as C#.

Let’s look at a simple object called printer. When you call the log method of printer passing in some other object, it will print the object passed in as well as the number of times the printer object has been used.

var printer = {
  callCount : 0,

  log : function(obj) {
    console.log("---");
    console.log(obj);
    this.callCount += 1;
    console.log("--- (log number: " + this.callCount + ")");
  }
};

As you can see, a very simple object with one field (callCount) and a log method. The log method will print the object, increment the field, and then print a line showing how many times it has been called. The use of this is not optional as in C#; it must be used, otherwise the interpreter will try to resolve it by walking up the scope chain to the Global Object (which in browser JavaScript is window). If you like, this bypasses the normal scoping rules in JavaScript.

Here’s a quick example of how to call it.

var someObj = {a:42};

printer.log(someObj); // prints 1 as log number
printer.log(someObj); // prints 2 as log number

The fun thing about JavaScript is that functions are objects. We can pass them around at will. Here’s a new (empty) printer object that I then create the same field for. I can then create a log method by copying the printer.log function.

newPrinter = {};
newPrinter.callCount = 41;
newPrinter.log = printer.log;

newPrinter.log(someObj); // prints 42 as log number

Function invocation

The next way of calling a function is using function invocation. This is easy in concept – just call the bare function, not using an object – but it is the invocation pattern that causes the most problems and bugs. The reason is that the this variable gets set to the Global Object. Let’s take a look at a couple of examples. Firstly though, let’s define a simple function that returns true if the passed in object is the Global Object.

var isGlobalObject = function(obj) {
  return (function() {return this === obj;}());
};

What? Did he say simple? Let’s take it slowly. First of all, isGlobalObject takes in an object and returns something. What it returns is the result of automatically calling an anonymous function. This anonymous function is called using the function invocation pattern we’re currently discussing and checks to see if this is equal to the outer obj parameter. In other words, this anonymous function makes use of the pattern we’re trying to demonstrate. (Note: because I did not hard-code window, this function will also work on node.js, where the Global Object is called something else.)

Before making moving on, let me emphasize a point. Automatically calling an anonymous function is one of the great patterns of modern JavaScript and hence in one of these types of functions this will point to the Global Object.

Now we can make up some example function and show that calling it using the function invocation sets this to the Global Object.

var doSomething = function (arg) {
  isGlobalObject(this) ?
    console.log("In this function, 'this' is the Global Object") :
    console.log("In this function, 'this' is something else");
};

doSomething(); // prints that 'this' is the Global Object

There is another common JavaScript coding pattern that can throw up bugs because people assume this points to the enclosing object rather than the Global Object, and that’s with callbacks. Let’s illustrate with setTimeout. I’ll write a ticker object that outputs an asterisk once a second.

var ticker = {
  show : function() {
    console.log("*");
  },
  start : function() {
    this.show();
    setTimeout(function() { this.start(); }, 1000);
  }
};

ticker.start();

If you run this code, you should see an asterisk, and then after a second you should get an error saying “this.start is not a function”. The reason is that the callback to the setTimeout function is an anonymous function and setTimeout’s code will call it using the function invocation pattern. The this variable will be set to the Global Object and not the ticker object, despite what a quick glance at the code might imply. Since window.start does not exist, you get the error message.

To solve this bug, we shall have to save the value of the this variable in the start method, and then use that local variable inside the anonymous function. Because in JavaScript scope is defined by function, the anonymous function will ‘see’ this local variable in its parent function.

var ticker = {
  show : function() {
    console.log("*");
  },
  start : function() {
    var self = this;
    self.show();
    setTimeout(function() { self.start(); }, 1000);
  }
};

ticker.start();

Notice that every time start is called, it is called using the method invocation pattern and we always save the object it’s called on in a local variable called self.

Constructor invocation

The third way of calling a function is using the constructor invocation pattern. The first point to make here is that you must use the new keyword when calling the function.

var Person = function(lastName, firstName) {
  this.firstName = firstName;
  this.lastName = lastName;
};

Person.prototype.print = function() {
  var name = this.lastName + ", " + this.firstName;
  console.log(name);
};

var me = new Person("Bucknall", "Julian");
me.print();

Here I’ve declared a function called Person, created a method via its prototype object, and then called the function using new. What this does is similar to C#: it creates a new object based on the template I gave. Person is not a class, even though creating a Person object looks like you’re creating an instance of a class. In essence, the new keyword will create a brand new empty object, set its constructor to the function, and then call the constructor. The this variable will be set to this new empty object.

The final unusual thing about constructor invocations is that the newly created and initialized object is returned by default; you don’t have to code up a return statement explicitly.

The big problem about the constructor invocation pattern is that you sometimes forget to use the new keyword. Constructors are normal functions, there’s nothing in the language that marks them as being anything special, and so suddenly the call turns into a function invocation. And we know all about those: this points to the Global Object. In my example: calling Person without new will create a two new properties on the Global Object (firstName and lastName), return and set me to undefined, and then crash on the next statement since undefined certainly has no method called print.

There is a bit of a hack that can get round this for you. Define your constructors like this, and you’ll avoid the problem of forgetting to use new.

var Person = function(lastName, firstName) {
  if (!(this instanceof Person)) {
    return new Person(lastName, firstName);
  }
  
  this.firstName = firstName;
  this.lastName = lastName;
};

In other words, if the this parameter is not an instance of Person assume that the caller forgot the new keyword and construct a new object properly and return it. If not, just proceed as normal for a constructor.

Apply invocation

The final way to call a function is to use the function’s apply or call methods. This is known as apply invocation. Yes, a function is an object, so it can have (and has) properties and methods of its own. Both apply and call work by calling the function on an explicit object that you supply. Arguments to the function are either passed one-by-one (call) or as an array (apply). (The way I remember which is which is to say Apply uses an Array because they both start with A.) The this variable is set to the first parameter of the call to call or apply. Here it is in action with our printer object from above:

var anotherPrinter = { callCount : 23 };
var someObj = { foo : 42 };

printer.log.call(anotherPrinter, someObj);
printer.log.apply(anotherPrinter, [someObj]);

All that’s happening here is that I’ve created an object (anotherPrinter) with a callCount field, and then applied the printer.log method to it, passing in some object to log.

Album cover for Geometry Of LoveNow playing:
Jarre, Jean Michel - Pleasure Principle
(from Geometry Of Love)

JavaScript for C# programmers: wrapping an existing function to add extra functionality

I was answering a JavaScript question on stackoverflow when a common usage scenario presented itself, one with a subtle gotcha that could catch you out. Perfect for a quick blog post. (Note: you could also view this post as an adjunct to my popular JavaScript callback posts (I, II, III).)

Pretty wrappingphoto © 2006 Judson Dunn | more info (via: Wylio)My solution to the problem involved adding some extra precondition code to an existing event handler. The event was the plotclick event of the jQuery Flot charting library, so the original event handler code looked like this:

  $("#chart").bind("plotclick", function (event, pos, item) {
    // respond to the click 
  });

Pretty easy stuff. However in my solution I wanted to enhance the event handler so that some preconditions were checked and, if they passed, the original code could be executed. Simple enough: just add the preconditions to the code – which is what I did for the answer.

  $("#chart").bind("plotclick", function (event, pos, item) {
    if (item) {
      var dataPoint = item.series.data[item.dataIndex];
      if (dataPoint[2]) {
        // respond to the click 
      }
    }
  });

For one chart, meh, not a problem. Make the change and move on. For several, it gets a little clunky; all those complicated bits of cut-n-paste. What would be better would be to wrap the original function – somehow – and then call the wrapper. In other words, in my mind I was thinking of something like this:

  $("#chart").bind("plotclick", wrap(function (event, pos, item) {
    // respond to the click 
  }));

So that the minimal amount of change would be required. This would also work if the event handler were not an anonymous function.

What would this wrap function look like? Well, it takes a function with the required signature (that is, takes three parameters) and returns another function, the event handler, that is also of the required signature and that calls the original function. (Call these the wrapper and the wrapped.)

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      // extra stuff
      originalHandler(event, pos, item);
    };
  };

There is, however, one small problem with this code. I will admit that the first time I wrote it I missed the issue, and it was only through testing that I discovered the bug, so it’s not glaringly obvious.

I’ll stop a moment for you to think about it.

Found it? Give yourself a bonus point if you did. The problem is the this variable, the context of the wrapper, is not passed on to the wrapped. As written, the call to originalHandler is a function invocation, and the this variable inside the function will be the global object, not the context passed in for the wrapper function. With jQuery, the context will be the DOM element for which the event was triggered, and my code just blithely throws that away.

Let’s rectify that right now:

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      // extra stuff 
      originalHandler.call(this, event, pos, item);
    };
  };
In other words, we use the Function call method to pass on the this variable on to the called function.

So, going back to my particular case, I’d have:

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      if (item) {
        var dataPoint = item.series.data[item.dataIndex];
        if (dataPoint[2]) {
          originalHandler.call(this, event, pos, item);
        }
      }
    };
  };

So, I’d say the takeaway from this blog post is that—yet again—the fundamental concept that functions are objects (that is, you can pass them around, and create functions that return functions), and that you should be careful if you do so that you take care of the this variable, if needed.

Album cover for Pieces In A Modern Style 2Now playing:
Orbit, William - Lark (alex metric remix)
(from Pieces In A Modern Style 2)


JavaScript for C# programmers: Function basics and scope

Another post in the occasional series on programming in JavaScript from a C# developer's viewpoint.

This episode: the basics of functions in JavaScript, especially with regard to scope.

All right, here we are, finally. Writing some real executable code. Before we do, however, I have some very important information, and I need to make it a header, so you remember:

Functions are objects

This one concept, I believe, more than any other you've met so far, is the defining difference between C# and JavaScript. All functions are objects. You can assign them to variables; you can pass them around, for example as parameters to other functions; you can call them in various weird ways; you can give them properties; you can do those funky "functional programming" things to them like currying; and even the very definition of scope is function-based in JavaScript.

I'm sure you can see that there's a huge amount of information you're going to have to grasp here, but, if nothing else, remember this: functions are objects. Drill it into your subconscious. I know from experience it won't get there immediately, but I'll try and help it along. Functions are not bits of named code attached forevermore to a single class, like they are in C#, but are separate entities that you can manipulate in various, very interesting ways, as well as call them.

Defining a function

Back in the first installment of this series, I introduced a simple function to test whether a number was finite:

function isFiniteNumber(value) {
    return ((typeof value === "number") && isFinite(value));
}

And in the previous episode I showed a function to test whether a value was an array or not:

var isArray = function(value) {
    return (value) &&
        typeof value === "object" &&
        value.constructor === Array;
};

The two declarations look very different. The first one (known as a function statement) looks like a simple routine as you might have written it in C or Pascal, in the days before OOP. It seems to exist as an individual entity, separate from everything else; the kind of routine you can't write in C#, because every routine has to be a method on a class. The second one (known as a function expression) looks like a variable that holds a function (in other words, an object).

In fact, they are exactly the same, and work in the same way. The only difference is a rare problem dealing with where in your code you can declare function statements (the hoisting problem: different browsers can do it in different ways and you could get different results from the same piece of code).

The general recommendation is to use the var declaration version, for a couple of reasons. The first and the main one is that it explicitly states that the function is an object. You can't gain any other impression from the declaration: here's a variable called isArray and here's the function object we're setting it to. Once we've set isArray to this function object, we can call it using the () operator if we want. The second reason is that it forces you to think differently about JavaScript functions and to understand that they're not simple blocks of code attached to a single class/object for evermore. In particular, in JavaScript we can change the function that a variable points to very easily, and the function statement variant makes us think that the function is fixed; it's not.

Scope

This one is hard for C# programmers. Despite the fact that JavaScript looks so familiar with its C-style syntax, it uses a very different set of scoping rules than does C# or Java. Before we discuss the way JavaScript does it, let's revisit what scope means. Scope is the means by which programmers limit the visibility and the lifetime of their variables and parameters. Without scope, all variables would be global (and I've programmed in such languages and never want to again). In C#, scope is introduced by braces: you can declare a new variable inside some code in braces — a block — and that variable would not be visible outside the block, and in fact would be destroyed once execution reaches the closing brace. It's the most important invention to avoid global name collisions ever made.

In C# these braces can be the braces surrounding the code in a method, they can be the braces delineating a block for an if or a for statement, and so on. The essence is: declare a variable inside a block and it won't be visible outside. (If you want to read the full details about scope in C#, see section 3.7 of The C# Programming Language (Third Edition) by Hejlsberg et al. There are two pages of rules.)

In JavaScript, there is one basic rule: functions define scope. If you declare a variable in a function, it is visible anywhere inside that function, including inside nested functions, even before it was declared. It is not visible outside the function. Let's take a look:

var test = function(value) {
    var a = 1;
    var b = 2;
    var nested = function() {
        if (b === 2) {
            var a = "some string";
        }
        console.log("nested: " + a);
        console.log("nested: " + b);
    };

    nested();

    console.log("test: " + a);
    console.log("test: " + b);
};

test();

OK, some nonsense code, but let's dissect it. First of all we're declaring a variable called test and assigning it a function to it (from now on, I'll save on my typing and just say "declaring a function called test"). At the end we call this function variable. The test function first declares three variables, called a, b, and nested, then calls nested (it's a function) and logs the values of a and b.

The nested function tests to see if b is 2, and if so declares a string variable called a. It then logs the values of a and b.

Let's talk about the scope of the various variables. First of all, inside test, a, b, and nested are visible everywhere. Also the parameter called value is visible there too. In particular, all these variables are also visible inside nested (and, yes, nested is visible inside nested: we can do recursion). So far, nothing too surprising.

Let's look inside nested now. If you had your C# hat on, you'd say that the declaration of the variable a is only visible inside the if block, and that the first call to console.log() would fail to even compile. In JavaScript though, this new declaration of a is visible everywhere in the nested function; it is not limited to the if block. The variable b, since it's not redeclared inside nested, comes from the outer scope, that is, test. So the result of calling nested() is this:

nested: some string
nested: 2

Since a in the outer scope wasn't changed (the inner scope redeclared it), the logging for the outer scope produces this:

test: 1
test: 2

Having said all that, let's do some thought experiments. By all means use FireBug to verify what I describe is actually what's going to happen. First I'm going to initialize the value of b to 3, and rerun. What happens now? The if condition evaluates to false, and the declaration of the redefined a doesn't get executed. What does the function log then? The value of the outer scope's a? Or something else?

The answer is "something else". In fact, you'll get an error that a is undefined, not because it doesn't exist, but that it does exist but has no value. Remember: a variable declared anywhere in a function is visible everywhere in the function. Technically speaking, the declaration of a variable gets hoisted to the top of the function. If you like, the JavaScript interpreter rearranges the function to look like this:

    var nested = function() {
        var a;
        if (b === 2) {
            a = "some string";
        }
        console.log("nested: " + a);
        console.log("nested: " + b);
    };

and then executes it. As you can see, a is declared but not initialized if b were equal to 3. The first call to console.log() would fail.

Return to the original code. This time we'll "forget" the var keyword on the a in the nested function. What happens now? Yes, you've guessed it: both sets of logging produce the same answer with a being output as "some string".  The scope rules say that a in the inner scope uses the declaration in the outer scope.

A harder one, now. Rearrange the code to look like this:

var test = function(value) {
    var b = 2;
    var nested = function() {
        if (b === 2) {
            a = "some string";
        }
        console.log("nested: " + a);
        console.log("nested: " + b);
    };

    nested();

    console.log("test: " + a);
    console.log("test: " + b);
};

test();

Notice I've removed the declaration and initialization of a completely from the test function and inside nested a is not declared with a var keyword. What happens now? Does it all fail disastrously?

Answer, no it doesn't. Both logging calls for a display the same value: "some string". How come, since a doesn't exist?

The reason is that if you assign a value to a variable that hasn't been declared with a var keyword, JavaScript first of all works its way up the various nested scopes looking for a declaration to use (as we saw above). If it can't find one having reached the very outer scope, it obligingly assumes you wanted to declare the variable as a property on the global object and does so. You are, in effect, declaring a global variable, and you just know how nasty that can be. The global object for JavaScript running in a browser is called window, and the code above is interpreted to mean this:

var test = function(value) {
    var b = 2;
    var nested = function() {
        if (b === 2) {
            var window.a = "some string";
        }
        console.log("nested: " + window.a);
        console.log("nested: " + b);
    };

    nested();

    console.log("test: " + window.a);
    console.log("test: " + b);
};

In other words, this is not another scope rule at all, in fact, the very opposite. You are creating a global variable visible everywhere in your code. Also just imagine how difficult this would make the code to read and understand if the very last line of test was "var a;", for then a would no longer be a global variable at all.

(If you look back, the functions isFiniteNumber, isArray, and the various examples of test are all global variables defined on the window object. If you like, they all become methods on window. Needless to say this could be very bad. What if there already variables with these names in the window object? I've just clobbered them, that's what.)

Three Important rules

We're learned three important rules in this post, rules that don't apply in the C# world at all:

1. Always declare your local variables at the top of the function with the var keyword. You don't have to, but you will save yourself some scope problems later down the line. Understanding scoping in JavaScript can be difficult enough when coming from C#, so don't make it worse for yourself. If you like, put your Pascal hat on and declare what looks to be a var block.

2. Always declare your functions as variables using the function expression syntax. It'll help you remember that functions are objects.

3. Understand that, if you forget to declare a local variable, it will be created for you as a property on the global object, and will be visible globally. Global variables are bad in JavaScript, just as they are bad everywhere else. Don't create them either inadvertently or deliberately. Minimize the pollution on the global object.

Identification

The constructor function is Function. The typeof operator, applied to a function object, returns the string value "function".

By the way: we haven't finished talking about functions yet. Still to come, for example, is the value of this. As you may already have guessed, it's not quite the same thing as in C#... Until next time!

Album cover for The Best of Thelonious Monk Now playing:
Monk, Thelonious - In Walked Bud
(from The Best of Thelonious Monk)


Search

About Me

I'm Julian M Bucknall, the M because it's my middle initial and because I and the other Julian Bucknall (the movie guy) would like to differentiate ourselves.

I'm a programmer by trade, an actor by ambition, and an algorithms guy by osmosis. I write articles for PCPlus in my spare time, not that there's much of that.

Julian M Bucknall Apart from that, an ex-pat Brit, atheist, microbrew enthusiast, Pet Shop Boys fanboy, slide rule and HP calculator collector, amateur photographer, Altoids muncher.

DevExpress

I'm Chief Technology Officer at Developer Express, a software company that writes some great controls and tools for .NET and Delphi. I'm responsible for the technology oversight and vision of the company.

Validation

Validate markup as HTML5 (beta)     Validate CSS

Bottom swirl

Archives

February 2012 (4)
SMTWTFS
« Jan  
1234
567891011
12131415161718
19202122232425
26272829

Like this Archive Calendar widget? Download it here.

Social networking

Google ads

The OUT Campaign

The OUT Campaign

My Tweets

Bottom swirl