2

I'm trying to understand "this" and everything I've looked at talks about context. What this has led me to is the idea that "this" is a scope limiter. It makes sure your variables are referenced using the proper scope, mostly by keeping variables "local" -ish in scope, and keeping them from reaching too far out from where the running code is.

My question is: is that correct? I tried to do searches using the concept I'm trying to get across, but those came up with totally bad results. There is a lot of nuance with "this", and from the reading I've done, I feel like this is a better explanation than what I've seen, but I want to make sure I'm correct in that thinking.

Huangism
  • 16,278
  • 7
  • 48
  • 74
NovaDev
  • 2,737
  • 5
  • 29
  • 43
  • 2
    Take a look at [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1) – Beterraba Jul 16 '14 at 14:32
  • 5
    The semantics of `this` really don't have that much to do with variable scope in JavaScript. – Pointy Jul 16 '14 at 14:33
  • I think you understand it right. – smk Jul 16 '14 at 14:33
  • 3
    "In JavaScript `this` always refers to the “owner” of the function we're executing, or rather, to the object that a function is a method of." - [quirksmode.com](http://www.quirksmode.org/js/this.html). I like that explanation. – Joseph Marikle Jul 16 '14 at 14:34
  • @JosephMarikle well that's not really true in JavaScript. Functions have no "owner", in any real permanent sense. – Pointy Jul 16 '14 at 14:38
  • @Pointy I don't have an exhaustive knowledge of the inner workings of javascript, so I wouldn't know. It's helpful for understanding what `this` means when your developing, but if you have a better resource on how javascript functions work, please do share. I would be very interested to find out myself. – Joseph Marikle Jul 16 '14 at 14:44
  • A [dup](http://stackoverflow.com/q/3127429/1169519)? – Teemu Jul 16 '14 at 14:48
  • [Here is a classic Stackoverflow question on the topic.](http://stackoverflow.com/questions/3127429/javascript-this-keyword) – Pointy Jul 16 '14 at 14:48
  • Here's a better reference on how "this" works in javascript:http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 . Better in the sense that it is more complete and also that I constantly update my answer if/when javascript evolves. – slebetman Jul 16 '14 at 14:53
  • @slebetman yes that's a good answer; it's more concise than the ones on those older questions. – Pointy Jul 16 '14 at 15:01

1 Answers1

3

this and variable scope are separate concepts. Variable scope refers to which variables can be accessed from where within your application. Just because you wrote var foo somewhere doesn't mean that you can access it from everywhere throughout your codebase. In Javascript each function introduces a new scope, and scopes nest in a way that inner functions have access to the scope of outer functions, but not vice versa.

this on the other hand is simply a "magic" reference to the "current" object. Maybe it's helpful to explain this idea in the context of other, classical languages first:

class Foo {

    protected $bar;

    public function baz() {
        echo $this->bar;
    }

}

In PHP the magic keyword $this refers to the current object instance. Each time you call new Foo, a new instance of this class is created. Every time you call $foo->baz(), the same function is executed, though with $this set to the appropriate object instance so each object instance can access its own data.

In Python this is actually a lot more explicit:

class Foo:

    def baz(self):
        print self.bar

Python does not have a magic keyword to refer to the current object instance. Instead, every method call on an object gets the current object passed explicitly as its first argument. This is typically named self. If Python seems too alien to you, the above in PHP syntax would be:

class Foo {

    public function baz($this) {
        echo $this->bar;
    }

}

Technically the functions in those classes do not really "belong" to any "class". They're just functions. You just need some way for those functions to be able to refer to a polymorphic object in order for them to be instance methods. Take for example:

function baz($obj) {
    echo $obj->baz;
}

That's essentially exactly the same as what the class method does above, with the difference being that $obj is explicitly injected instead of $this being magically "there".

Javascript has the same thing, except that this is available in every function (not just "class" functions) and that the object this points to can be freely changed at runtime. this is simply a magic keyword that points to an object, period.

function Foo() {
    this.bar = null;

    this.baz = function () {
        console.log(this.bar);
    }
}

When calling regular functions on objects like foo.baz(), this typically refers to foo inside of baz(); though it really doesn't have to:

foo.baz.apply(someOtherObj);

This takes the function foo.baz and calls it while setting the this keyword inside baz to someOtherObj. It freely re-associates the function with another object instance, if you will. But only because the only thing that "bound" the function to the object in the first place was the this keyword anyway. The function will still simply do console.log(this.bar), whatever this.bar refers to.


A more complete example:

function Foo() {
    this.bar = 'baz';
}

Foo.prototype.speak = function () {
    alert(this.bar);
};

var o = new Foo();
o.speak();    // alerts 'baz'
alert(o.bar); // also alerts 'baz'

var o2 = { bar : 42 };
o.speak.apply(o2);  // alerts 42

As you can see, this doesn't limit the scope of anything. What's happening here?

  1. The Foo constructor is called with new Foo(). new simply creates a new object and executes Foo() with this set to this new object. Basically:

    var tmp = {}; // tmp does not *actually* exist,
                  // that's more or less what `new` does behind the scenes
    Foo.apply(tmp);
    
  2. The Foo constructor assigns the bar property of that new object.

    tmp.bar = 'baz';
    
  3. The new object is assigned to o.

    var o = tmp;
    
  4. o.speak() is a function bound to that object through its prototype. Calling it as o.speak(), this inside speak() refers to the o object. Because that object has a property bar, this works.

  5. Notice that it's also possible to do alert(o.bar). The .bar property was set on this originally, then this became o. So o has the property .bar, which is a regular property of the object. It's not scope limited or anything.
  6. Next, we simply create another object o2, which also happens to have a bar property. Then we call o.speak, but we explicitly override the choice of what this refers to using apply. We simply do a switcheroo on what object the this keyword refers to. Thereby the speak function alerts the bar property of the o2 object.

As you see (hopefully, I know this can be brain bending at first), this is nothing more and nothing less than a reference to an object. That's all. It doesn't limit at all the scope of anything. functions limit scopes, this is just an arbitrary object. Anything you set on this is not limited in scope; on the contrary, it's always publicly accessible from anywhere you have access to the object.

It's incredible how trivial it all is once you manage to wrap your head around it. this refers to an object, it is simply Javascript's magic keyword to refer to an object. There are certain trivial rules which object it refers to at any given time, but all those can be bend and broken and reassigned. An object is simply a thing with properties. The properties can be functions. Only functions limit variable scope. That's pretty much all there is to it. Don't try to interpret anything else into this.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • So my question comes in when I think about creating an object. If I'm within the object, I create a variable, reference the variable within the same object, I have to use "this"; otherwise, the variables don't work right, because the scope is automatically not within the object, even though it's more local than the outer environment, because when using varName:value you can't use "var" to declare the variable within the object as only within the object. It will get over ridden by another variable of the same name outside of the object. So you limit the scope of that variable by using "this". – NovaDev Jul 17 '14 at 17:31
  • Not really, no. Please see my update. The best advice I can give is to take this all at face value. `this` refers to an object, period. Functions limit scope, period. Nothing more. You can build *usage patterns* on this which do one thing or another, and maybe you're referring to some particular design pattern, but `this` by itself does not limit scope. – deceze Jul 17 '14 at 17:56