6

I can claim that 'this' keyword is the most confusing part of Javascript for those who comes from languages like C#.

I have read a lot about this on the internet and on StackOverflow too. like here and here.

I know that 'this' keyword will be bound to the context. and in constructor function it will be bound to the object being created, and when there is no immediate context it will bound to global object (i.e window)

I know all that , however confusion is still not fully cleared; So the best way to understand is by testing codes.


So I decided to write small code and I was surprised by how much convoluted the this keyword.

here is the code i tested:

 function sayHi(name){ var tt = name; return { ss: tt, work: function(anotherName){ alert ("hiiiii " + anotherName); } }; } //this method invocation has no effect at all right now sayHi("John"); var hi2 = new sayHi("wallace"); hi2.work("May"); alert(hi2.ss); 

as expected the alert window will show (Hiiiiii May ) then ( wallace). Notice now that the line sayHi("John"); has no effect at all.

and Now the confusion will start when I change one thing ONLY (change var tt => this.tt):

 function sayHi(name){ //this is the ONLY change I did. this.tt = name; return { ss: tt, work: function(anotherName){ alert ("hiiiii " + anotherName); } }; } // Now this line invocation will be problematic sayHi("John"); var hi2 = new sayHi("wallace"); hi2.work("May"); alert(hi2.ss); 

the result surprised me when the alert mthod gave ( Hiiiiiii May ) and then (John) not (wallace);

so I had the idea to comment the line sayHi("John"); but that resulted in the whole code being no-functional and not working.

the demo is here

I know this might be newbee question. But it is really confusing here and I did try to read many articles and SO questions but i m missing this point.

Why does the line sayHi("John"); setting the hi2.ss to John?? and why does it break the code when we delete it ; although we invoke the sayHi method by using the new keyword afterward ??

3
  • In "strict" mode, this is undefined when a function is invoked without any context. Commented May 30, 2014 at 13:16
  • ss: tt, is assigning based on a local var, not a property of this, since the var doesn't exist it should be undefined. Commented May 30, 2014 at 13:17
  • @scragar after reading the answers down and understand all of them . now your comment make sense . thanks man Commented May 30, 2014 at 13:39

3 Answers 3

6

Because you assign the parameter "name" to a property of the object referenced by this (which in this case will be window), your subsequent reference to "tt" in that object literal will be to the "tt" property of the global object, since that's the next enclosing scope.

Your first call to "sayHi" is made without the new operator, so in that call this will refer to the global object (window). The first line in the second version

this.tt = name; 

therefore will set window.tt to "John".

The next call is made with the new operator. Because of that, this in the function refers to the newly-instantiated object. The line

this.tt = name; 

will therefore really have no net effect on anything, because the function returns a different object in all cases. The last line of your test:

alert(hi2.ss); 

says "John" because that's what's in window.tt. Why does that matter? Because "sayHi" returns an object with a property ("ss") set from the value of the symbol "tt". The only "tt" in scope will be window.tt, which was set back in the first call to the function.

Sign up to request clarification or add additional context in comments.

4 Comments

thank for you answer .. but still im confused. so you say that when I invoke sayHi("john") the 'this' is (window) and then it is window.tt = john... but why when I invoke the method again with new object created (hi2) the hi2.tt is still john not wallace?? im confused still.. appreciating further illustration
It's "John" because in the second call, this is not window - you call it with new.
great clarification. appreciating your patience , but now my question is as follow : first call sayHi("john") gave me a variable (window.tt = "john"); but the second call (hi2 = new sayHi("wallace") should give me another variable ( hi2.tt = "wallace") .. are you saying that tt is not allowed locally since it is set up globally??
No, it's not hi2.tt - it's the brand new object that's created due to your calling the function via new. The first line of the function will succeed in setting that object's "tt" property to "wallace", but then you set "ss" to just plain "tt" and not "this.tt".
3

When you first invoke sayHi("John");, this will point to the global object window. That means this.tt = name actually creates a global tt variable.

Then when you invoke new sayHi("wallace");, this correctly points to a new instance of sayHi, but you are returning another object instead of letting new naturally return the instance.

If you carefully look at your object literal, you define ss like ss: tt,. Since you aren't using this.tt and there is no tt symbol found in the constructor's scope, the value will then be resolved as a global variable (which was previously set to John).

4 Comments

I love you man .. although all answers here are informative; however you alerted me about the object literal mistake I did. when I define the ss:tt to ss:this.tt the behavior of the code is as expected ... now I figured it out.
am I allowed to edit your answer so I add the code in its correct format?
@stackunderflow I'm glad I could help. Instance variables attached to this and function-scoped variables declared with var are two very distinct things. Accessing a variable on it's own e.g. someVar rather than this.someVar or obj.someVar will never resolve to an object member (except global variables wich are properties of window in a browser).
@stackunderflow Usually it's not an accepted practice to modify the content of an answer, unless you are not changing it's meaning. This usually means that you cannot do much more than fixing grammar mistakes or typos. The answer's creator is not the only one involved in the editing approval process and your edit might very well be rejected by people that are foreing to this conversation. It's usually best to leave a comment and let the answer's owner deal with it.
3

When invoking a constructor function, if no return statement exists in the function then this is implicitly returned otherwise the return value is returned and this is simply ignored.

In your second example you are saving the name argument as this.tt but returning a different object. That's why things aren't working. Basically use this or return a custom object, but don't do both.

2 Comments

That's not really the issue. I think the OP is well-aware that he's overriding the implicit return. The OP's confusion is more about why ss: tt doesn't result in his expectations.
@plalx: My answer does explain why ss: tt doesn't result in his expectations.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.