0

Consider the following code:

  function Plant () {
        this.country = "Mexico";
        this.color= "yellow";
    }

    Plant.prototype.showDetails = function() {
        console.log("I am from " + this.country + " and my color is " + this.color); 
    }  

    var banana = new Plant();
    banana.showDetails(); //this outputs "I am from Mexico and my color is Yellow".

Now my question is, how does showDetails get access to country and color properties of Plant function even though it is outside the function? (Javascript has scopes as per functions, lexical scoping).

I did some introspection and found that when banana.showDetails is invoked, 'this' refers to Plant object and not banana object. Why is this so? In JS, 'this' refers to the object that calls the function, which in this case is the banana object.

darKnight
  • 3,344
  • 8
  • 30
  • 59
  • because youre adding showDetails to the Plant prototype, simple as that. – omarjmh Jun 05 '16 at 21:05
  • 1
    "*'this' refers to Plant object and not banana object.*" That's not entirely accurate. `this` does refer to `banana`. The "*Plant object*" probably refers to the "*instance of Plant*," which is banana in the snippet, not the constructor function itself. – Jonathan Lonowski Jun 05 '16 at 21:07
  • `.country` and `.color` are properties, not variables that would be scoped lexically. It's really just accessing the properties of the object that is bound to `this` - which happens dynamically when you call `banana.showDetails()` – Bergi Jun 05 '16 at 21:13
  • possible duplicate of [How does the “this” keyword work?](http://stackoverflow.com/q/3127429/1048572) - it doesn't really matter that the method is inherited from a prototype object. – Bergi Jun 05 '16 at 21:19
  • @Jonathan Lonowski : when I do console.log(this) inside the showDetails method, it outputs Plant {country: "Mexico", color: "yellow"} in console. This is weird, as Plant is not an object, but a function. The output should have been banana {country: "Mexico", color: "yellow"} if this was referring to banana object. – darKnight Jun 05 '16 at 21:26
  • @dk49 The console is just displaying the constructor that was used when creating the object as "*meta*" information to help with debugging, and `Plant` is that constructor. If you log a plain `Object`, say `console.log({})`, it will appear in a similar manner – `Object {}`. The portion in braces, `{ ... }`, is still the actual contents of `banana` itself. – Jonathan Lonowski Jun 05 '16 at 21:27
  • @Jonathan Lonowski: Thanks for the clarification. But is there a way to check the name of actual object that is being printed in the console rather than its constructor? – darKnight Jun 05 '16 at 21:35
  • @dk49 `{country: "Mexico", color: "yellow"}` is the value of `banana` rendered as text. It is logging the actual object. The mention of `Plant` is in addition to that value and only added by the Console. (Try `console.log(Plant)` for comparison, which would log only the constructor.) – Jonathan Lonowski Jun 05 '16 at 21:38

2 Answers2

1

country and color are not properties of the Plant function; they are properties of whatever object was bound to this when Plant was called.

Doing new Plant() creates a new object, then calls Plant with this bound to the new object.

(In some sense, every JavaScript function has two parameters, this and arguments, which are set by every function call (disclaimer: does not apply to "fat arrow" style functions).)

The following code is morally equivalent to your code, just without using constructors/methods:

function Plant(x) {
    x.country = "Mexico";
    x.color = "yellow";
    return x;
}

function showDetails(x) {
    console.log("I am from " + x.country + " and my color is " + x.color); 
}  

var banana = Plant({});
showDetails(banana);
melpomene
  • 79,257
  • 6
  • 70
  • 127
  • Do you mean to say that 'this' (which is pointing to the object which called the property/method) gets passed to the prototype object when the javascript interpreter fails to find that property/method in the local object? – darKnight Jun 05 '16 at 21:54
  • @dk49 Objects aren't passed to other objects. Things get passed to functions. (Getting a property from an object follows the prototype chain.) I'm not sure what you're asking. – melpomene Jun 05 '16 at 22:45
0

You created banana object as a new Plant object, since you're not defining it's own properties it uses properties defined in Plant. If you define properties on banana, like this: banana.country = "Serbia"; banana.color = "red"; then you'll get values from banana properties. So basically this refers to banana but banana uses properties inherited from Plant.

Jovica Šuša
  • 602
  • 3
  • 8