Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugultopu/577d10a4c3900e4667d5c18a90fa4e73 to your computer and use it in GitHub Desktop.
Save ugultopu/577d10a4c3900e4667d5c18a90fa4e73 to your computer and use it in GitHub Desktop.
Observe how does "this" propagates to the inner functions

Code:

function usesThis(name) {
  this.myName = name;

  function returnMe() {
      return this;        //scope is lost because of the inner function
  }

  return {
      returnMe : returnMe
  }
}

function usesThat(name) {
  var that = this;
  this.myName = name;

  function returnMe() {
      return that;            //scope is baked in with 'that' to the "class"
  }

  return {
      returnMe : returnMe
  }
}

console.log('returnMe result is', new usesThat('Dave').returnMe());
console.log('returnMe result is', new usesThis('John').returnMe());

Output:

returnMe result is usesThat {myName: "Dave"}

returnMe result is {returnMe: ƒ}

As you can observe, the value of the initial context was not preserved (reflected) in the inner function when we tried to access the initial context value using "this" variable. For information, the "context" is the value of "this" variable at the time the constructor is called. A constructor is nothing but a function which has been called with the "new" keyword.

My guess for the reason of this behavior is that I think "this" is a keyword, not a variable. Hence, in the example that uses "this", no closure for the inner function is created since it is not using any variables at all from the outer context (assuming "this" is a keyword and not a variable). Whereas in the example that uses "that", a closure must have been created because the inner function is using a variable that is defined outside of it (that is, defined in the outer context). This allows us to access the value of the context at the time the constructor was called.


Technically, you can still define a "class" without using the 'this-that "hack"' as:

function usesThis(name) {
  function returnMe() {
    return this;
  }

  return {
    myName: name,
    returnMe,
  }
}

// Or, more simply:
function usesThis(name) {
  this.myName = name;
  this.returnMe = function() {
    return this;
  }
}

This would work. However, it wouldn't have "encapsulation". That is, it wouldn't be a proper "class" because what should have been a "private member" (which is the name or myName attribute) is exposed to the public in this implementation. Hence, this implementation does not create a proper "class" because of the lack of "encapsulation".

Addendum: According to MDN, "this" is indeed a keyword, instead of a variable.

Credits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment