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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
hackerhasid
  • 11,699
  • 10
  • 42
  • 60
  • Why do you want to set the context explicitly? Your examples doesn't really show that. Either you'll have to pass a context into the alertT-function or you'll have to use a bind-method to bind the function to a context of your choise – Jakob Oct 07 '10 at 16:32
  • The example was dumbed down so it's easy to read. I want to be able to explicitly access the closed over variable for the purposes of passing that into another, passed in, function. – hackerhasid Oct 07 '10 at 16:35

3 Answers3

1

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
  • 118,147
  • 33
  • 203
  • 236
  • 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 Oct 07 '10 at 16:31
  • 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. – hackerhasid Oct 07 '10 at 16:32
  • @jakob, absolutely. Seems OP is just trying to understand how the scope works in closures though, and this is just an example – hvgotcodes Oct 07 '10 at 16:33
  • 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 Oct 07 '10 at 16:35
  • Jakob -- no way to do it explicitly, huh? That's very annoying! – hackerhasid Oct 07 '10 at 16:36
  • @statichippo: Kind of :) But that's really not needed. I've written an answer for you. – Jakob Oct 07 '10 at 16:48
1

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.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 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) – Ruan Mendes Oct 07 '10 at 18:05
0

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
  • 24,154
  • 8
  • 46
  • 57