5

I found this example code:

function personFullName() {
    return this.first + ' ' + this.last;
}

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
}

var dude = new Person("Michael", "Jackson");
alert(dude.fullName());

Which alerts "Michael Jackson". I changed it to call personFullName from the constructor instead of assigning the function object:

function personFullName() {
    return this.first + ' ' + this.last;
}

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName();
}

var dude = new Person("Michael", "Jackson");
alert(dude.fullName);

I would expect the "fullName" property to now be a string instead of a function. But now it alerts "undefined undefined". Can anyone explain why my version doesn't work?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
random_stuff
  • 197
  • 2
  • 12
  • 5
    See this answer for a full explanation of how `this` works: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman May 19 '15 at 15:07

4 Answers4

6

In JavaScript, this is typically whatever comes before the . in the function call. So the fact that you said dude.fullName() is what caused this in fullName() to be set to dude1.

In the second version in your question, you're not calling it the same way. You're calling personFullName() without anything in front of it (which is correct, since it's no longer attached to a Person object). That means that this ends up defaulting to the same value as window. Since window has no first or last properties set on it, this.first and this.last are undefined.

To fix this, you can make your person be an argument to the personFullName() function:

function personFullName(person) {
    return person.first + ' ' + person.last;
}

and then call it like

…
this.fullName = personFullName(this);

1: Note that the method has to be a property on the object for the this binding to work. You can't just call object.someMethod() and get have this set to object in someMethod. In your code, the following would not work:

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = this.personFullName();
}

Uncaught TypeError: this.personFullName is not a function

Neither would this:

function personFullName() {
    return this.first + ' ' + this.last;
}

function Person(first, last) {
    this.first = first;
    this.last = last;
}

var dude = new Person("Michael", "Jackson");
alert(dude.personFullName());

Uncaught TypeError: dude.personFullName is not a function

You can get around this restriction in any situation with the apply helper method: this.fullName = personFullName.apply(this) does what you expect the second version of your code to do and you can also call personFullName.apply(dude) at any point and get "Michael Jackson" back.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
1

this is the window in your personFullName function as it wasn't called in the correct context. You can use apply to call it with the correct context without modifying the personFullName function.

function personFullName() {
    return this.first + ' ' + this.last;
}

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName.apply(this); // The magic
}

var dude = new Person("Michael", "Jackson");
alert(dude.fullName);
Matt Derrick
  • 5,674
  • 2
  • 36
  • 52
1

A better alternative to fix that would be:

Person.prototype.personFullName = function() {
    return this.first + ' ' + this.last;
}
War10ck
  • 12,387
  • 7
  • 41
  • 54
Staplerz
  • 85
  • 1
  • 10
0

The context in which your are accessing this in your second example, is referencing the window object. window has no fullName property set to it. If you add alert(this); to both functions you'd see what I mean.

Leon
  • 38
  • 5