3

I am trying to understand some basic javascript .

I have the following snippet. We have the name variable which in both cases are referenced over getName Method.

First alert outputs HocusPocus, while the second one outputs GeorgeThomas. But I do not understand how this refers to name in this case

    var name = 'Gerorge Thomas';
    var obj = {
       name: 'Cinderella',
       value: {
          name: 'HocusPocus',
          getName: function() {
             return this.name;
          }
       }
    };
    
   alert( obj.value.getName() );
   var testing = obj.value.getName; 
   alert(testing());
deroccha
  • 1,007
  • 4
  • 17
  • 35

3 Answers3

4

To understand this issue, you have to understand how Javascript sets the value of this in a function call.

There's a summary of all the methods here: When you pass 'this' as an argument

For your particular case, when you do this:

var testing = obj.value.getName; 

You now have a reference to the getName function. You no longer have any connection at all to obj.value. So, test() just calls getName as an ordinary function. In Javascript when an ordinary function call is made, then the value of this will be either the global object (window in a browser) or in strict mode, it will be undefined.

In your case, this becomes the window object so this.name is window.name which points to the global variable name and thus you get the result 'Gerorge Thomas'.

In fact, if you run your code in strict mode, it will cause an error which is, in fact, one of the benefits of strict mode that it points out accidental errors like this.


On the other hand, if you execute a function with the form of obj.method(), then this is set to be obj. So, when you do:

obj.value.getName()

that is equivalent to:

var o = obj.value;
o.getName()

which is the obj.method() form of calling a function which will set the this pointer to be the object, which in this case is obj.value.


It is possible to work around this issue in a couple of ways. Here's an example of working around it using .bind().

var name = 'Gerorge Thomas';
var obj = {
  name: 'Cinderella',
  value: {
    name: 'HocusPocus',
    getName: function() {
      return this.name;
    }
  }
};

document.write( obj.value.getName() + "<br>");
var testing = obj.value.getName.bind(obj.value); 
document.write(testing());
Community
  • 1
  • 1
jfriend00
  • 580,699
  • 78
  • 809
  • 825
2

Well it only needs some reflection, let's analyse it:

  • In the first alert we are calling the getName() method of the obj.value object so it returns obj.value.name which is "HocusPocus".

alert( obj.value.getName() ); we call this.name where this refers to obj.value so name is HocusPocus

  • But in the second alert we are creating a new function testing() with the body of the getName() method, so it will be attached to the global window object and if we call it we will get the global name value wich is 'Gerorge Thomas'.

alert(testing()); we are dealing with this.name where this refers to the global scope so name is 'Cinderella'.

cнŝdk
  • 28,676
  • 7
  • 47
  • 67
1

First, you're calling a method from inside the obj object. The 2nd time, you're making a copy of the function (not really, it's just a reference) in the global scope. So you could also write window.testing() for the 2nd call. I think that makes it clear.

DanMan
  • 10,431
  • 3
  • 36
  • 57
  • There's no copy of the function being made at all - there's still only one function. There's an assignment of the function reference to a second variable. But, that assignment has nothing to do with the OP's issue. The issue is purely in how the function is called. – jfriend00 Sep 11 '15 at 16:51
  • A minor, technical detail that doesn't really matter here, but I shall take your word for it. – DanMan Sep 11 '15 at 16:54
  • @DanMan - it's the entire premise of your answer and it is not correct. It doesn't actually matter whether `testing` is in the global scope of not. Even if it's in a function scope, the same problem exists. This doesn't have to do with the global scope. – jfriend00 Sep 11 '15 at 16:56
  • It is all explained in my answer. When you call `obj.method()`, the `this` pointer inside of the execution of `method()` is set to `obj`. So, in your second example, you've attached a new method to `obj2` named `getName` and you've called it with `obj2.getName()` so, of course, the `this` pointer in that method will point to `obj2`. You may want to read [this other answer](http://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676) about how `this` is set in Javascript. – jfriend00 Sep 11 '15 at 17:11
  • So it obviously is all about scope. Anyway, feel free to vote me down. – DanMan Sep 11 '15 at 17:22
  • It's not about scope at all. It's about how `this` is set based on how a function is called. – jfriend00 Sep 11 '15 at 19:24