8

I am learning javascript and i came across a doubt. Why is the value of "this" undefined in the first example , but prints out correctly in the second.

example 1:

var myNamespace = {
    myObject: {
        sayHello: function() {
            console.log( "name is " + this.myName );
        },
        myName: "john"
    }
};

var hello = myNamespace.myObject.sayHello;

hello(); // "name is undefined"

example 2:

var myNamespace = {
    myObject: {
        sayHello: function() {
            console.log( "Hi! My name is " + this.myName );
        },
        myName: "Rebecca"
    }
};

var obj = myNamespace.myObject;

obj.sayHello();//"Hi! My name is Rebecca"

Why does the value of "this" changes within the function. What concept am i missing?

Gabe Moothart
  • 28,997
  • 13
  • 73
  • 98
poorvank
  • 7,210
  • 17
  • 54
  • 102
  • 4
    That's how `this` works. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this – SLaks Oct 09 '13 at 16:19
  • 2
    Your expectation is just fine, JavaScript's `this` semantic is broken. :-) – Waldheinz Oct 09 '13 at 16:20
  • it is javascript not "java script".. very very great difference.. :) – Mr_Green Oct 09 '13 at 16:21
  • @Waldheinz JavaScript `this` is more closely akin to the "receiver" concept in languages like SmallTalk than it is like the `this` concept in C++, Java, and/or C#. – Pointy Oct 09 '13 at 16:21
  • Possible duplicate : http://stackoverflow.com/questions/16832062/the-scope-of-this – Lorenz Meyer Oct 09 '13 at 16:22
  • 2
    Basically, the problem is that in Javascript, `this` is not bound when you access the method in the object (as in, say, Python), but only when you call it. So it's literally "the object to the left of the `.` in the actual method call expression." In your second example, that's `obj`, in your first example you don't call the method using the dot syntax so it's nothing. (And you can also choose what the value of `this` will be by using `Function.bind()` or when using `Function.call()` and `Function.apply()`, just to make things more complicated. jQuery does this pervasively.) – millimoose Oct 09 '13 at 16:28
  • 1
    1 example, hello is the function, 2 example hello is object myObject; function sayHello has no myName defined, while myObject has – Dart Oct 09 '13 at 16:29
  • See my related answer here for a complete explanation of how "this" works in javascript: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman Oct 09 '13 at 18:32
  • I just answered one of your question, and you deleted it without even a comment. I find this of very bad taste. – Denys Séguret Oct 10 '13 at 06:43
  • @millimoose - I don't know if it's 100% technically accurate but I find your "object to the left of the `.` in actual call" metaphor way easier to understand than every other explanation I've ever read. You should consider making it a proper answer so it gains more visibility. – Álvaro González Oct 10 '13 at 09:29

2 Answers2

4

First case you are just getting the reference of the function to the vairable hello, and invoking it from global context (window in browsers, global in node), So this becomes what invoked the function except for (bound functions). You can always set the context explicitly using function.call or set the context explicitly to the function using Ecma5 function.bind

hello.call(myNamespace.myObject); //now you are setting the context explicitly during the function call.

or just bind it while getting the function reference.

var hello = myNamespace.myObject.sayHello.bind(myNamespace.myObject); //Now no matter where you call it from `this` will point to the context of myObject

Second case you are invoking it from the object itself so this points to the object.

PSL
  • 120,386
  • 19
  • 245
  • 237
1

In the first case, the implicit this object is the global scope. Because there is no myName in the global scope, you get undefined.

If you want a free function with the proper this, use bind:

var hello = myNamespace.myObject.sayHello.bind(myNamespace.myObject);
SheetJS
  • 20,261
  • 12
  • 60
  • 74