0

I have some JS code where I want to return my global object's instance in its child method (think fluent interface):

myGlobalVar = function() {
    this.self = this;
    this.Whatever = function() {
        //return self; // why does that FAIL??
        return this.self; // why does that WORK??
    }
}

I would have assumed that I'd return self but that fails. return this.self succeeds but I figured this in the child function would refer to said function. Why does this work?

Haney
  • 32,775
  • 8
  • 59
  • 68
  • there is no free-floating variable "self" to return... the meaning of this does not change in the child function as shown. – dandavis Jan 22 '14 at 03:01
  • Why is that so, @dandavis ? – Haney Jan 22 '14 at 03:02
  • you have no var keyword or arguments, so there are no named variables. – dandavis Jan 22 '14 at 03:02
  • in other words, you can just "return this" since this==self... – dandavis Jan 22 '14 at 03:09
  • @dandavis Why does the meaning of `this` not change in the child function? – Haney Jan 22 '14 at 03:11
  • The instance can be hit inside the constructor and inside own methods as this, so it's really just a mis-understanding more than an actual problem. if you detach from the instance or apply/call when using the method, you can change the meaning of this. but if you call myGlobalVar.Whatever(), this==myGlobalVar inside. also, self is used already, so use something else like "that" to avoid potential conflicts down the line. – dandavis Jan 22 '14 at 03:12
  • is it running in a strict mode – Arun P Johny Jan 22 '14 at 03:14
  • see http://jsfiddle.net/arunpjohny/f9JXN/1/ – Arun P Johny Jan 22 '14 at 03:15
  • @ArunPJohny: that's just the pre-defined global self making an appearance... – dandavis Jan 22 '14 at 03:16
  • @dandavis yes... that is why I'm confused... unless op is not using it as a constructor both should work – Arun P Johny Jan 22 '14 at 03:18
  • You will need to differentiate between *property* and *variable*. See [Javascript: Do I need to put this.var for every variable in an object?](http://stackoverflow.com/questions/13418669/javascript-do-i-need-to-put-this-var-for-every-variable-in-an-object) – Bergi Jan 22 '14 at 04:39

2 Answers2

2

In javascript the value of this in a function is determined by the caller of the function.

When you call obj.method(), the value of this is set to obj inside of method(). So, in your example above, when you call myGlobalVar.Whatever(), the value of this inside of Whatever() will be myGlobalVar so to reference sefl, you use this.self as you have discovered.

self all by itself does not work because it is not a variable in the current scope all by itself. It's a property of myGlobalVar and thus can ONLY be referenced as either myGlobalVar.self or this.self when this === myGlobalVar. Javascript does not automatically check properties on the current object in order to resolve a symbol. You can only reach a property of an object by specifically referencing the object that hosts the property as in this.self.


There are other ways that the value of this can be altered. If Whatever() is called without the obj context such as:

var fn = myGlobalVar.Whatever;
fn();

Then, the value of this will be either the global object in regular JS or undefined in JS strict mode.


There are also .call() and .apply() methods on every function that allow you to directly specify what you want the this value to be set to inside the method as in myGlobalVar.Whatever.call(myOtherGlobalVar).

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

When you try and access a variable, JavaScript, first look for that variable in the current function scope, next, in the enclosed functions scope and then finally in the global scope. In your case, self is a member of this, global object. When you say this.self, and if this refers to the global scope, this.self is same as the self. Unless you change the current context, this will refer to the global object and it should work. Check the following example to understand better.

myGlobalVar = function() {
    this.self = "thefourtheye";
    this.Whatever = function() {
        console.log(self);
        console.log(this.self);
        console.log(this.self === self);
    }
}

var b = {
    self: "thethirdeye"
}

myGlobalVar();
Whatever();
console.log("-------------------");
Whatever.apply(b);

Output

thefourtheye
thefourtheye
true
-------------------
thefourtheye
thethirdeye
false

When I am calling Whatever, the second time, I am setting the current context to object b, with apply. So, now this points to b. Now, self is different from this.self. When I refer self, it looks up the hierarchy and finds self in the global scope, it prints thefourtheye, when I say this.self, it looks up self in b and it prints thethirdeye. Hope its clear now.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • how does this.self return correctly for OP if 'this' will not be available in Whatever()? – dandavis Jan 22 '14 at 03:06
  • @dandavis We are not returning `this.self`, we are returning `self` :) – thefourtheye Jan 22 '14 at 03:06
  • 1
    i meant that you said "The problem here is this. You are making a reference to this, in this itself. So, it will not be available within Whatever", when clearly the OP can indeed see this and it's property "self". – dandavis Jan 22 '14 at 03:07
  • @thefourtheye try my code, it works. Why does it work if `this.self = this`? – Haney Jan 22 '14 at 03:09
  • Can't give the answer out twice, but you get an upvote for sure. Thanks for the explanation! – Haney Jan 22 '14 at 14:37