Monthly Archives: April 2011

The this Keyword and Scope

As my first post on this extremely powerful, yet fundamentally flawed language, I will look at the function/global object conundrum.

First, a bit of background. A function in Javascript is a block of executable code which is invoked (simplified definition). A method, however, is a function in an object. I just wanted to distinguish between the two, because it is fundamental to the point of this post.

When you have a method defined in an object, and you invoke that method, the call object is passed in to that method and is accessible with the keyword this. For example, consider the following methods inside this person object:

            // "person" written as a plain object
            var person = {
                showName: function () { return this.name; },
                setName: function (newName) { this.name = newName; }
            };

Here, this is a memory reference to the object stored in the variable person. However, consider what happens when I add the following function to the page:

            function GlobalFunction() {
                this.person = 'Dave';
            }

How is this bad? Consider the full page:

<html>
	<head>
        <script language="javascript">

            // "person" written as a plain object
            var person = {
                showName: function () { return this.name; },
                setName: function (newName) { this.name = newName; }
            };


            function pageLoad() {
                person.setName('Dave');
            }

            function GlobalFunction() {
                this.person = 'Dave';
            }
                
        </script>

	</head>
	<body onload="pageLoad();">
        <input id="PersonObjectButton" type="submit" value="submit" onclick="alert(person.showName());" />
        <input id="GlobalFunctionButton" type="submit" value="submit" onclick="GlobalFunction();alert(person);" />
	</body>
</html>

On invocation of pageLoad, I invoke the setName method of the person object and pass in ‘Dave’. I then click the PersonObjectButton which calls showName(), and the string “Dave” is displayed in a pop-up. However, if I then click GlobalFunctionButton, the this keyword in GlobalFunction refers to the Global object. The person object which was created on the page load is blown away completely and replaced with a string. (Remember, Javascript is loosely typed. The same variable can be a person one minute, then a string the next).

This can be seen by inspecting the DOM elements using Firefox’s awesome Firebug plugin:

personGlobalVariableOnPageLoad

Figure 1

You can see from Figure 1 that the Global object (Window) has a variable called person which is an object (with a name variable etc.). That is the object assigned to person upon page load.

personGlobalVariableOnButtonPress

Figure 2

However, in Figure 2, the Global object has a variable called person which is now a string. The original person object is now garbage-collected, whilst the person string lives on. Not a good result if you only intended the expression this.person = ‘Dave’; to have its lifetime confined to the GlobalFunction function.

It’s probably not a great example, as the GlobalFunction function is completely pointless. (Why would anyone intend to assign a value to a private variable then exit the function straight away?).

However, it does illustrate how easy it is to blow away global variables if the developer does not understand the point which I am illustrating in this post. (And believe me. Developers don’t understand many things about Javascript. Even experienced ones.)

In my next post, I will demonstrate how to achieve privacy for a variable inside a function (which was not achieved in the function above).

Some Client-Side Telerik Sweetness

One of the many great things about the Telerik controls is their easy-to-use client side API.
I recently had to write some javascript to do that thing where you are filling in your address details, and you check a box to copy your street address to your postal address (to save the user from typing their address details out again). I also had to change the colour of the postal address if the user clicked another checkbox. Filtering out the insignificant code, it looked something like this:

string chkAddressScript = string.Format(
                    string.Concat(
                        @"function copyAddress() {{",
                        ...
                        @"var postState = document.getElementById('{5}_Input');",
						...
						@"var resState = document.getElementById('{11}_Input');",						
						...
                        @"}}"), ..., PersonDetailsControls.FindControl("drpPostAddrState").ClientID,
                        ..., PersonDetailsControls.FindControl("drpResidentialState").ClientID,
                        ...);
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "chkAddressScript", chkAddressScript, true);

The trick here is to get a hook on the dom element for the Telerik control’s input part by using the _Input suffix. You can then easily change it’s colour with:

	var resState = document.getElementById('<% PersonDetailsControls.FindControl("drpPostAddrState").ClientID %>');,	
	resState.style.color = 'red';,					

Aint it just grand!