Friday, November 29, 2013

What's "this"? What's "this"?

tldr; (for me):
Be very careful when it comes to "this" in javascript, and err on the side of caution, always confirming via examples if in doubt.
What's this?
Jack Skeleton wants to know, too

This is a short note on the javascript notion of "this", illustrated via a few examples. Conceptually, the "this" variable is set to the caller object that is calling a function.

You would think this kind of definition would allow a fairly straightforward determination of "this", but I don't think this is always the case. It can require a thoughtful consideration of the execution context that is actually relevant when the method is called, and there is at least one kind of edge case where it depends on whether you have strict mode enabled or not.

This short note does not include how the new operator affects "this". Or how call and apply come into play (these actually seem a bit more straighforward). And things are more involved for the case of eval, which is also not included here (see "Eval breaks all the rules").

The table below lists a few examples, a couple of which kind of surprised me. I plan to add more.

ExampleWhat's this?
Calling function from global context

function f() {
     whatsThis(this);
}
//called in main script (i.e., not 
// from another function or object)
f();
The global object

[object Window]
Calling method on object from global context
(object first defined as empty object literal)

var myObject = {};
myObject.f = function() {
     whatsThis(this);
  };
//called in main script (i.e., not 
// from another function or object)
myObject.f();
The object upon which method was called

[object Object]
Calling method on object from global context
(object created by returning it from function,
method is set to internal function of the object)

var aMadeObject = (function() {    
  function g() {
      whatsThis(this);
  }
  
  return {gg:g};    
  
  })();
//called in main script (i.e., not 
// from another function or object)
aMadeObject.gg();
The object upon which method was called

[object Object]
Event handler for html element
(event handler added by setting "onclick" in code)

  <div id="someElement">Click me</div>
  
  var myElem = 
     document.getElementById('someElement'); 
  
  myElem.onclick = function() {
     whatsThis(this);
  };
  
The element that was clicked
(__proto__ is HTMLDivElement in Chrome)
Event handler for html element
(event handler added inline in html, using "this")

  <div id="anotherElement" 
    onclick="whatsThis(this);">
         Click me, too</div>
  
  
The element that was clicked
(__proto__ is HTMLDivElement in Chrome)
Event handler for html element
(event handler added inline in html, "this" not passed)

  <div id="yetAnotherElement" 
    onclick="someOtherMethod();">
         Click me please</div>
  
  
The global object
  (from within "doSomething()")
Calling internal method of object from within object

var myObjectWithInner = {};

myObjectWithInner.f= function() {    
    function onlyInnerFunction() {
      whatsThis(this);
    }    
    onlyInnerFunction();            
};
//called in main script (i.e., not 
// from another function or object)
myObjectWithInner.f();
Not in strict mode:
   [object Window] (!)

In strict mode: undefined
Links
Note
The little images were pasted from the Chrome DevTools inspector window. I looked into the Chrome DevTools source to see if there were a straigtforward way to generate the relevant html for them by adapting the DevTools js code. It was interesting to learn more about how DevTools works, but it did not seem straightforward to use it as I wanted (starting place seems to be blink/Source/devtools/front_end/ConsoleMessage.js).

No comments:

Post a Comment