This and that - Javascript identity crisis

March 20, 2013

If you usually program in a language such as C#, you’ll be used to the this keyword.  If you aren’t then in C#, this means this; that is, it means the current object that you’re calling this from.  For example, you might have a class called house, which has properties called DoorOpen and WindowOpen, and a method called ShutTheDoor:


    class House
    {
        public bool DoorOpen {get; set;}
        public bool WindowOpen { get; set; }

        public void ShutTheDoor()
        {
            this.DoorOpen = false;
        }
    }


And the calling code:



    class Program
    {
        static void Main(string[] args)
        {
            House house = new House();

            house.DoorOpen = true;
            house.ShutTheDoor();
            Console.WriteLine(house.DoorOpen);


        }
    }

That makes sense to me. The object House contains the method ShutTheDoor AND the property DoorOpen, so I can call one from the other. As a matter of fact, this is even optional. Any property or method inside House will recognise DoorOpen. I can call this from anywhere, and it will have the same behaviour; for example:


    public void ShutHouseDoor(House house)
    {
        house.ShutTheDoor();
    }

In Main:



    house.DoorOpen = true;
    HouseMinder minder = new HouseMinder();
    minder.ShutHouseDoor(house);
    Console.WriteLine(house.DoorOpen);

How does Javascript deal with this then? Well, pretty much the same way for the most part (the code samples here are using WinJS):

[sourcecode language=“javascript”]

house: WinJS.Class.define(
    function() {},
    {
        doorOpen: true,
        windowOpen: true,
        shutTheDoor: function shutTheDoor() {                
            this.doorOpen = false;                
        }
    }
)



**The Problem**

So that's cool - it works in the same way.  Well, not quite; say I want a program that shuts the house door when I click the canvas:

[sourcecode language="javascript"]
            var body = document.getElementById("body");
            var canvas = document.createElement("canvas");
            canvas.id = "houseCanvas";

            body.appendChild(canvas);

            var canvasContext = canvas.getContext("2d");

            canvas.width = window.outerWidth;
            canvas.height = window.outerHeight;

            canvasContext.fillStyle = "#f00";            

            canvas.addEventListener("MSPointerUp", house.shutTheDoor, false);

That’ll work, right - because shutTheDoor calls this.doorOpen. Well, and for me this is the most annoying thing about javascript, it will certainly compile. However, when it calls shutTheDoor, it calls in on the canvas, not on the house class. Let me say that again: NOT ON THE HOUSE CLASS.

So it’ll fall over?

No.

What it actually does it helpfully realise that you’ll called a property (this.doorOpen) which doesn’t exist, so it simply creates it for you and sets it to false… on the canvas object.

The Solution

[sourcecode language=“javascript”] canvas.addEventListener(“MSPointerUp”, house.shutTheDoor.bind(house), false);




The .bind tells javascript to use the object that you're passing as the context.

**Conclusion**

Javascript's dynamic creation of properties can be useful, but I can't help thinking that problems like this are why statically typed languages are always going to be easier to work with.  You get your first unit test for free: it compiles.  In Javascript, not only will an incorrectly named property compile, it will exist - even if it doesn't.


Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2024