0

I saw the code below in a text book on closures:

var name = "The Window";

var object = {
  name: "My Object",
  getNameFunc: function () {
    return function () {
      return this.name;
    };
  }
};

alert(object.getNameFunc()()); // "The Window"

A detailed explanation on why the this object in the inner function cannot access the object scope but rather accesses the global scope could be of great help.

Thanks for the help.

ronnie
  • 11
  • 2
  • @JamesDonnelly, I fixed those in the edit. – Andy Aug 11 '15 at 15:10
  • Essentially, in javascript EVERYTHING is an object, even a function. So when you create an anonymous function, it is an object and thus has a this pointer for it. The standard way of dealing with this is to declare a variable before the function like var self = this, then use that instead. – nurdyguy Aug 11 '15 at 15:17
  • 1
    Didn't mean to sound demanding but need your guys@andy@michael – ronnie Aug 11 '15 at 15:19
  • EVERY function call in Javascript sets a new value of `this` based on how the function was called. The value of `this` is never automatically preserved from one function call to the next. See [How `this` gets set](http://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676) for the 5 ways that the value of `this` gets controlled. – jfriend00 Aug 11 '15 at 15:32
  • That is the how but I wanna know why the this object changes in an anonymous function.what brings this about?@nurdyguy @jfriend00 – ronnie Aug 11 '15 at 15:45
  • Because EVERY single function call in Javascript sets a new value of `this`. If there is no specific way that `this` is purposefully set (e.g. one of the 5 ways listed in my previously linked answer), then `this` is set to `window` or `undefined` (if in strict mode) and that's what you're seeing. The last function call in `object.getNameFunc()()` is just a normal function call which causes `this` to be set back to the global object. It is how Javascript works. In your case, you can either use `.bind()` or you can use `var self = this;` in the parent function and then refer to `self`. – jfriend00 Aug 11 '15 at 15:47
  • I added an answer that covers what I've said in comments. – jfriend00 Aug 11 '15 at 15:58

3 Answers3

0

Break it down into separate function invocations. Instead of

 object.getNameFunc()()

let's break that down, call the first function, then invoke the result of that.

 var theFunc = object.getNameFunc(); // invocation 1
 theFunc();   // invocation 2

in invocation 1 we call getNameFunc(), and we specify a context (we have something before the . ) So within that invocation "this" has a specified value, object

In the second case we are calling the function "bare", no specified context, so we have the global context.

djna
  • 54,992
  • 14
  • 74
  • 117
0

In getNameFunc(), this refers to object. It returns a function which is not bound to a context, just to the containing scope. The context (what this refers to) is not inherited (although scopes are).

Inner functions do not inhert the context which they are defined in, although they do inherit the scope they are defined in.

One way to work around this is to .bind() the returned function to the context:

getNameFunc: function () {
  return function () {
    return this.name;
  }.bind(this);
}
Tobias
  • 7,723
  • 1
  • 27
  • 44
  • Don't get you .... Are you saying that variable object or lexical context are not inherited? – ronnie Aug 11 '15 at 15:38
0

In Javascript, every single function call causes a new value of this to be set and if it is just a plain function call, then this is set to either the global object (which is window in a browser) or undefined (if running in strict mode). That's what is happening for you. In this line:

object.getNameFunc()()

object.getNameFunc() makes the first method call and returns the internal anonymous function. Then, the last () is just a regular function call of that function and that regular function call causes this to get set to the global object (window in your case). Any plain function call resets the value of this to window or undefined. This is how Javascript works.

Here's a simple demo that show you how this is reset:

See this answer for the five ways that the value of this is controlled.

You can work around this issue in several ways by either saving the value of this in the parent function or using one of the methods to explicitly control the value of this.

One of the simpler mechanisms to understand is to just save the value you want in the parent function:

var myName = "The Window";
    
var object = {
  myName: "My Object",
  getNameFunc: function () {
    var self = this;
    return function () {
      return self.myName;
    };
  }
};

document.write(object.getNameFunc()()); // "My Object"

Or, you can use .bind():

var myName = "The Window";

var object = {
  myName: "My Object",
  getNameFunc: function () {
    return function () {
      return this.myName;
    }.bind(this);
  }
};

document.write(object.getNameFunc()()); // "My Object"

FYI, I changed your variable name to myName so there could never be any confusion in following what was happening with window.name which already exists in the browser environment.

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