views:

53

answers:

3

I've seen a bunch of examples but can't seem to get some sample code to work.

Take the following code:

var test = (function(){
    var t = "test";
    return {
        alertT: function(){ 
            alert(t);
        }
    }
}());

and I have a function on window.load like:

test.alertT();

That all works fine. However, when I try to explicitly set the context of t inside the alert() in alertT, I just get undefined.

I've tried:

var that = this;
alert(that.t); //undefined

I've tried:

        return {
            that: this,
            alertT: function(){ 
                alert(that.t); // undefined!
            }
        }

and I've tried:

var test = (function(){
    var t = "test";
    var myObj = this;
    return {
        alertT: function(){ 
            alert(myObj.t); // undefined!
        }
    }
}());

what am I missing? I need to be able to set the context explicitly for things like callbacks etc. I've seen examples too (http://stackoverflow.com/questions/346015/javascript-closures-and-this-context) that seem like what I'm doing, so why does this not work?

+1  A: 

t is not on the scope of 'this'. t is a variable local to the method. So somewhere you need to do

this.t = whatever

...

here is a real life example from an app I am writing

var scope = this;

cells.forEach(function(cell, index) {
            var given = cell.get('given');

            var value = cell.get('value'),
                            valueAsString = '%@'.fmt(value);


             var rowValues = scope.getRowForIndex(index);
            ...
}

the scope inside the forEach function is the scope of the array 'cells' over which I am iterating. Since I want to do things on the calling scope, I use a closure...

hvgotcodes
True. But that can be a bad idea as well. If "this" is the global object in that method, a global variable will be created.
Jakob
but since this is a closure, if I just reference t I get the closed over t because the function itself does not contain any t variable. I'm really interested in knowing how I can explicitly refer to the closed over t within the method.
statichippo
@jakob, absolutely. Seems OP is just trying to understand how the scope works in closures though, and this is just an example
hvgotcodes
statichippo: you said it yourself. You'll get the closed over t by not having any t in the inner function itself. There is no way to do itexplicitly. "This" is very different in javascript compared to C# and Java etc
Jakob
Jakob -- no way to do it explicitly, huh? That's very annoying!
statichippo
@statichippo: Kind of :) But that's really not needed. I've written an answer for you.
Jakob
+1  A: 

t is just a normal variable in the scope of the outside anonymous function (and thus also the inner anonymous function). It isn't a property on an object, so you simply set it without reference to this, that, or the_other.

var test = (function(){
    var t = "test";
    return {
        alertT: function(){ 
            alert(t);
        },
        setT: function (new_value) {
            t = new_value;
        }
    }
}());
test.alertT();
test.setT('hello, world');
test.alertT();

The syntax you are using is the usual pattern for creating something that acts like a private variable in JS.

David Dorward
I couldn't figure out what statichippo was asking until I saw your answer. I'm guessing he thought that "this" was a reference to the scope containing the closure variables? Good explanation. My advice is not to use "this" unless you're writing OO "class like" code where "this" refers to the object being manipulated, which this example could easily be changed to. But as you mentioned, this module patttern gives you truly private variables (which make it harder to debug)
Juan Mendes
A: 

In C# and Java, one can do something like this:

public class MyClass {
    private int x;

    public void DoSomething(int x) {
        int a = this.x;
        int b = x;
    }
}

The variables a and b will have values from different x's, since one is the class's x an one is the methods x.

Now, imagine if you could not use this to explicitly refer to the the class's x. Then you'd have to do the following:

public class MyClass {
    private int classX;

    public void DoSomething(int x) {
        int a = classX;
        int b = x;
    }
}

That i the situation you have in JavaScript, pretty much. At least in the situation you're describing. By using the methods apply and call you can change the context that a function is executed in, but you can never distinguish variables with the sames names but different scopes. You'll simply have to use different names for that.

Jakob