0

I know this subject had been dealt a lot here, but I saw this specific example on the Pluralsight JS design pattern course, and I'll be glad for your help understanding the closure there.

This is the example:

var Calc = function(start) {
    var that = this;

    this.add = function(x) {
        start = start + x;
        return that;
    };

    this.multiply = function(x) {
        start = start * x;
        return that;
    };

    this.equals = function(callback) {
        callback(start);
        return that;
    };
}

new Calc(0)
    .add(1)
    .add(2)
    .multiply(3)
    .equals(function(result){
        console.log(result); // returns 9
    });

Here's the JSFiddle link: http://jsfiddle.net/3yJ8Y/5/

I'll be VERY glad for:

  1. Understanding the "that" use. Why do we need it in this specific example? it does the same with "this". Can you pls give examples and explain when do we need to do "var that = this"?
  2. Understanding this way of creating functions from an object. why do we have to use "this" and then .functionName? like this.add = ...
  3. A detailed and extensive explanation for this very specific closure example.

Thank you so much!

FED
  • 317
  • 1
  • 2
  • 12
  • `that` is actually wrong here (since it's not a local variable). `this` would've been better. – Bergi Feb 26 '14 at 01:32
  • You don't need `that` in this case, `this` will work just fine, see http://jsfiddle.net/3yJ8Y/2/ – elclanrs Feb 26 '14 at 01:33
  • 1
    What exactly don't you understand about the closure? Was there no explanation at the course, at what point did you get lost? `start` is a local variable to every `Calc` invocation. – Bergi Feb 26 '14 at 01:34
  • I added the "var" before "that", sorry for the typo. I do understand the use of the "start" var in the closure. I'll be glad for explanations for what I wrote there. Thanks! – FED Feb 26 '14 at 01:36
  • This is what you need http://stackoverflow.com/questions/3127429/javascript-this-keyword. `new` does some magic but the important thing to understand is how `this` works. Bottomline, `this` depends on how you call a function, it can be implicit or explicit. – elclanrs Feb 26 '14 at 01:38

2 Answers2

1

Thanks to @elclanrs for reminding me of things I had internalized and forgotten...

That

The important thing here is that that... is unnecessary.

I'll quote an article that @elclanrs linked in his comment on the above post:

Scope In Javascript

JavaScript establishes an execution context for the function call, setting this to the object referenced by whatever came before the last ”.”

Because each method is called with the outer Calc before it's dot, the this value inside that method is assigned as the outer object.

The outer object, in turn, is its own brand new, self-contained scope because it was created with the new keyword:

When new[Calc]() is executed, a completely new object is created transparently in the background. [Calc] is called, and its this keyword is set to reference that new object.

(Scope in Javascript, again, with my edits in brackets).

Now you might be wondering, "How is this:

.add(1)
.add(2)
.multiply(3)

... keeping the right scope? You said that whatever is before the . is passed in as the this variable in this situation!?"

Absolutely true, and in this situation, each method is returning this, which allows method chaining. (They're actually returning that, but we already determined that was an unnecessary variable in this context).

Why use that

First of all, let me say I prefer var self = this over var that = this but there are arguments either way.

Let's arbitrarily modify the object to have a method that looks like this:

this.getInternalThis = function(){
    var internalThis = function(){
        console.log( this );
    }
}

First of all, let's get this out of the way: this example is stupid, but you'll see things like this - a function defined in other scopes - all the time.

Here are the important things to notice:

  1. It's called by name, and nothing more (no prefixed . notation, for example)
  2. ... that's it!

When a function is called this way, the engine has to figure out something to assign this as in the scope of the function. It defaults to window. If you were to run this code, you would get Window in the console.

Now, what if we wanted this inside that internal function call to be the calling value of this? This situation is where you need a that variable. We can modify the function to look like:

this.getInternalThis = function(){
    var that = this,
        internalThis = function(){
            console.log( that );
        };
}

Now when you run this method, you get the value of the calling object in the console.
In my case it was Object { add=function(), multiply=function(), equals=function(), getInternalThis=function()}.

Sometimes, that's what you need or expect, so that's why you would use a var that = this declaration.

Using this. to define a method

As I mentioned earlier:

Because each method is called with the outer Calc before it's dot, the this value inside that method is assigned as the outer object.

Remember that this in the scope of Calc() is a reference to the new Calc object, so each method is being given the Calc object as the value of this (remember, it's before the .!) when they enter their new scope from that context.

Hopefully this gives you a little info on how JavaScript scopes and the assignment of this works.

rockerest
  • 9,847
  • 3
  • 33
  • 67
  • I think this explanation is misleading, `this` isn't assigned to anything until the function is called. It is the `new` keyword which creates a new object for `this`, otherwise it will default to `window`. The reference to `that` is unnecessary in this case because using dot notation on the instance implicitly sets `this` to be the receiver. Using prototypes doesn't make `this` magically refer to the instance, it is the way you call the function that matters. – elclanrs Feb 26 '14 at 01:52
  • @elclanrs You're very right. Could you edit my answer or post another to make that clear? – rockerest Feb 26 '14 at 01:55
  • Thank you so much guys!! – FED Mar 01 '14 at 00:16
0

start becomes a global variable of the Calc object

Each method of the Calc object (add, multiple, equals) references that same global variable

new Calc(0)            // <- sets start to 0
    .add(1)            // calls add() <- sets start to 1
    .add(2)            // calls add() <- sets start to 3
    .multiply(3)       // calls multiple() <- sets start to 9
    .equals(function(result){
        console.log(result); // returns 9
    });
jasonscript
  • 5,189
  • 1
  • 23
  • 39