Wednesday, October 8, 2014

If you are surprised by how "this" works in JavaScript

If you are surprised by how "this" works in JavaScript, then you don't understand the fundamentals of JavaScript method invocation.

Twenty years ago when I was programming in C++ and learned COM, I recall the list of 12-15 of items that detailed the rules on how memory was allocated and freed across COM object method invocations. My peers would study and memorize these rules, and often use them for Interview questions. When I learned the rules, I had a "duh" moment because the COM rules were just a byproduct. There was no need to memorize them because there was only one possible way it could ever work. I used logic rather than memorization.
I see the same thing today with new JavaScript programmers who expect "this" to behave as it does in C++ or C#. Then they run into problems. They learn form their mistake but their approach is that "this" doesn't work right. Here's where it's broken and you have not the exceptions.
"this" in JavaScript is not like irregular verbs in English grammar. There's no exceptions to the rule. The key is to stop thinking that it's like "this" in Java. It's not.
The best explanation of how "this" works to date is Yehuda Katz' article on "Understanding JavaScript Function Invocation and 'this'". It's an old article, but it's best I've seen.
If you want a simple rule of thumb, it goes like this: 1. When you call a function like method using the syntax obj.method, as in: myObject.myMethod(), then mObject is passed in as a hidden parameter named "this" and can be used from within the myMethod() function. 2. If you call a function without using the method invocation, as in: myFunction(), then referencing "this" inside of the function does something you probably don't want, such as access to the global variable (like window) or it doesn't point to anything. It depends where your code is running. Don't use "this" inside of a function that's not invoked as a method invocation.
Now, if you have an object, myObject, that has to methods, myMethod1() and myMethod2(), if you call myObject.myMethod1(), "this" inside of myMethod1() will be myObject. However, if inside of myMethod1() you call myMethod2() without the object method invocation, i.e. you simply call myMethod2() directly, like you would in Java, C# and C++, then this will not get passed as a hidden parameter.
Your response should be "well duh, of course it wouldn't". But if you think "wtf? why!" then go read Yehuda's article.
[edit] One more point of clarification: In order to use a method invocation syntax, the method has to be a property of the object. That is, the right side of the dot, the method, has to be known by the object. In order for a.b() to work, b has to be in the property list of a. As long as the identifer exists, the syntax will be allowed.