2

Trying to understand this, found an example in javascript the good parts book:

var first;
var second;

var Quo = function(string) {
    first = this;
    this.status = string;// first this
};

Quo.prototype.get_status = function() {
    second = this;
    return this.status;//second this
};

var myQuo = new Quo( "confused" );
console.log( myQuo.get_status() );

console.log( (first===second) + ',' + (second===myQuo) + ',' + (first===myQuo) );

Output:

$ node test.js 
confused
true,true,true

Does the first this and the second this both point to myQuo? How to print out the object name or function name or class name which each this point to? (Really confused by this currently.)

UPDATE

Another questions: Both this refer to the instance of Quo instead of Quo's prototype?

Also, trying:

console.log( myQuo.get_status() );
console.log(first.constructor.name);
console.log( first );
console.log( second );

Output:

confused

{ status: 'confused' }
{ status: 'confused' }

Why first.constructor.name is nothing? Why first is { status: 'confused' }?

BAE
  • 7,178
  • 12
  • 57
  • 136

4 Answers4

2

In javascript, when a function defined on a prototype is called on an instance; "this" inside the function means (think like it is replaced with-) that instance (or the owning object having the prototype in its prototype chain).

In your case the constructor (which is also a function on the prototype) is called with a newly created object as "this" with the "new" keyword.

var Quo = function(string) {
    first = this; //this is the newly created instance
    this.status = string;// first this
};

Then first is also assigned the exact same instance.

When get_status is called on the same instance, this is again replaced with the instance;

Quo.prototype.get_status = function() {
    second = this; //this is myQuo
    return this.status;//second this
};

and this time second is assigned the same instance.

doing myQuo.get_status() is same as;

Quo.prototype.get_status.call(myQuo)

Therefore these two "this" keywords refer to the same object.

Doing the "===" check is perfectly fine to compare if two variables point to the same instance. Getting the constructor name just tell you they were constructed with a specific constructor name, not else. It is possible to make two different objects with the same constructor name.

Ali Naci Erdem
  • 435
  • 2
  • 12
  • both `this` refer to the instance of Quo instead of Quo's prototype? – BAE Nov 11 '16 at 20:57
  • Yes, they refer to the instance. – Juan Mendes Nov 11 '16 at 20:58
  • Exactly. Think about calling the functions on the prototype with .call or .apply with the object instance as "this". – Ali Naci Erdem Nov 11 '16 at 20:59
  • 1
    It really has nothing to do with `Object.prototype` that the `this` context gets replaced, in that `Object.prototype` is not unique. It has to do with the fact that the function `get_status` is being called on an owning object, therefore the this context is set to that of the owning object. – mhodges Nov 11 '16 at 21:02
  • 1
    "*when a function defined on a prototype is called; the lexical "this" inside the function means (think like it is replaced with-) the instance of that prototype object*" is not necessarily true. *this* is set by how a function is called, or use of *bind*. The only lexical *this* is from arrow functions. The function declaration in the answer is not syntactically correct. – RobG Nov 11 '16 at 21:09
  • I'm the king of edits now. I think the last version is as close as I can get :) – Ali Naci Erdem Nov 11 '16 at 21:15
  • @RobG To expand on my comment, I have posted an answer. I think you'll like it – mhodges Nov 11 '16 at 21:17
2

This question is solely centered around this and context within JavaScript.

Whenever you question What is this? You should always ask yourself these 4 questions (in order) and you will always get your answer.

  1. Was the function called with the new keyword?

    Example: var myObj = new Obj();

    This: The newly created object

  2. Was the function called with call, apply, or bind with the this context explicitly passed?

    Example: myFunction.call(self)

    This: this inside myFunction will be equal to self

  3. Was the function called via a containing/owning object?

    Example: myObj.myFunction()

    This: this inside myFunction will be equal to myObj

  4. What is the default this context?

    This: If in strict-mode, default is undefined. If not in strict-mode, default is the global object

So, in your case:

first = this is inside the Quo function, and is called using the "new" keyword, therefore first will equal the newly created object.

myQuo is simply the return value of executing the Quo function with the "new" keyword, which returns the newly created object by default, so that is why first === myQuo

second = this is inside of the get_status() function, which means nothing until the function is called. Once the function is called, you can see question 3 above, to see that the this context will be bound to the owning object. Since it was called with myQuo.get_status(), myQuo is the owning object, which is why second === myQuo.

Hopefully this clears everything up! Let me know if you need additional explanation!

mhodges
  • 9,573
  • 1
  • 22
  • 43
  • P.S. I have these 4 questions written on a sticky note which sits on my monitor at all times for reference - quite handy! – mhodges Nov 11 '16 at 21:19
  • 4. is confusing. _Am I running strict mode? Context: this will default to the global object (except in strict mode)_ How to run strict mode except strict mode? Also the example is not complete. – Ali Naci Erdem Nov 11 '16 at 21:31
  • @AliNaciErdem Your comment is pretty nit-picky, to be honest.. especially the strict-mode example being incomplete. I'm not here to explain how strict mode works. I did re-word the question, though, to remove any ambiguity. – mhodges Nov 11 '16 at 21:40
  • You forgot to mention fat arrow (for completeness), it doesn't matter how it's called – Juan Mendes Nov 11 '16 at 22:09
  • @mhodges I also found that if `myQuo.get_status()` not called, second is undefined. I am confused. I thought the object `Quo.prototype` already exists before `myQuo.get_status()` called. – BAE Nov 12 '16 at 02:21
  • Note that "context" typically refers to an execution context. *this* is just one parameter of an execution context, it's not **the** context. Instead of "*…the this context will…*" you should just say "*…this will…*". ;-) – RobG Nov 12 '16 at 05:15
  • @RobG That's a fair point. I think saying the "this context" would be correct, but I think it could be confusing when I just say "context". I will change it accordingly. Thanks for the insight – mhodges Nov 14 '16 at 16:47
  • @BAE The reason it is undefined before you call `myQuo.get_status()` is because code inside of a function never gets executed before it is invoked. Therefore, `second`'s value will be determined at run time of the function. If you were to invoke it on myQuo2, second would be equal to myQuo2. – mhodges Nov 14 '16 at 16:51
1

Does the first this and the second this both point to myQuo?

Correct they both point to the same instance of Quo.

How to print out the object name or function name or class name which each this point to?

console.log(first.constructor.name);
console.log(second.constructor.name);
Esteban Felix
  • 1,541
  • 10
  • 20
0

Here's an explanation of how this works in the two cases you mentioned. First, you need to understand that this is set depending on how the function is called (unless we're dealing with fat arrow functions )

When calling new

var myQuo = new Quo( "confused" );

It's basically the same as doing

var myQuo = Object.create(Quo.prototype);
// Explicitly setting `this`
Quo.call(myQuo, "confused")

When calling a function on an object

myQuo.get_status()

Implies that the get_status function will be called with what's to the left of the ., that is, myQuo.

  • You can never now the name of an object (if you mean that this is named myQuo)
  • To get a reference to the constructor function, you can do myQuo.constructor (or this.constructor). If your function is named (as yours is), you can use this.constructor.name to get Quo.
Juan Mendes
  • 80,964
  • 26
  • 138
  • 189
  • Your answer lacks completeness by omitting call, apply, bind, and default this context – mhodges Nov 11 '16 at 23:34
  • @mhodges But my answer explains that I'm only talking about the cases the OP mentioned, I did not attempt to give a thorough explanation as your answer did ;) `Here's an explanation of how this works in the two cases you mentioned` I only added that comment to your answer because you did attempt a thorough explanation. – Juan Mendes Nov 11 '16 at 23:45