Can someone help me explain why the first example works, but the second doesn't.
// Define a class
function Foo(name) {
var self = this;
this.name = name;
this.greeting = function() {
console.log('Hello ' + self.name);
}
}
var foo = new Foo('foo');
foo.greeting();
var greeting = foo.greeting;
greeting();
Output:
Hello foo
Hello foo
// Define a class
function Foo(name) {
this.name = name;
}
// Greeting
Foo.prototype.greeting= function () {
console.log('Hello ' + this.name);
}
var foo = new Foo('foo');
foo.greeting();
var greeting = foo.greeting;
greeting();
Output:
Hello foo
Hello undefined
My guess would be because the first example is using closure, so it retains the reference to the name
local variable, but the second example is not, and since greeting()
method is invoked without object context, it defaults to undefined
.
Many answers, all with useful and correct information, but none of them explains the behavior correctly.
In your first example, it only logs Hello foo
both times, because you're creating a variable self
which references the this
object. That self
variable is then closured in your greeting function
. Hence, you can call that function however you want, it'll always access self.name
and not this.name
so its always the same.
You don't do that in your prototype
example. There you directly access this.name
and then it is indeed important of how the function is invoked (see @lwburk answer).
So again, even if you call the first example like
foo.greeting.call( window );
it would still access the closured self
variable and log Hello foo
.
There are four ways to invoke a function in JavaScript, each of which changes the value of this
inside the function:
As a global function call: greeting()
. The value of this
is the global window
object (in browsers).
As a method on some object: foo.greeting()
. The value of this
is the object instance on the left-hand side of the .
operator (foo
).
As a constructor: new greeting()
. The value of this
is a new object that is created and implicitly returned from the function. This is used to create new objects.
Using call
or apply
: greeting.apply(someVal, someArgs)
. The value of this
is the object passed as the first argument (someVal
).
Any function can be executed in any of these four ways (although not all functions should be executed in some of them).
In the first case you're performing a method call:
var foo = new Foo('foo');
foo.greeting();
...so this
is foo
inside the function. In the second case you're performing a global function call:
var greeting = foo.greeting;
greeting();
...so this
is window
inside the function.
Edit: Note @jAndy's answer which points out the more salient issue in this case, which is that greeting
closes over self
in the first example (regardless of how it's called), but does not in the second (which then makes how the function is called relevant).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With