Reputation: 33
With parentheses when calling sayIt
function.
function Fruit(type){
this.type = type;
this.taste = "Awful";
this.thought = sayIt();
}
function sayIt(){
return this.taste+" "+ this.type;
}
window.onload = function (){
var lemon= new Fruit("Lemon");
alert(lemon.thought);
};
This will alert "undefined undefined", why?
sayIt
function without parentheses.
function Fruit (type){
this.type = type;
this.taste = "Awful";
this.thought = sayIt;
}
function sayIt(){
return this.taste +" "+ this.type;
}
window.onload = function (){
var lemon= new Fruit("Lemon");
alert(lemon.thought);
};
This will literally write down the function on the alert box, why?
Thank you in advance.
Upvotes: 3
Views: 176
Reputation: 95598
I'm assuming there is a typo in the first example and you meant to write alert(lemon.thought())
. The reason you're seeing undefined undefined
is because this.thought
is set to the return value of the sayIt
function. In the sayIt
function, this
refers to the window
object and not the Fruit
object. Since window
doesn't have a taste
or type
property, you will see undefined undefined
.
In the second example (I'll again assume you have a typo and you meant to do alert(lemon.thought())
), you this.thought
is set to be a reference to the sayIt
function, so you're not actually calling it. When you alert a reference to a function, it will print out the source of that function.
BONUS
You can get it to work the way you want if you do this:
this.thought = sayIt.call(this);
This will set the this
to point to the Fruit
object and now sayIt
will return what you want.
In the second example, you will get what you want if you do this:
alert(lemon.thought());
lemon.thought
refers to sayIt
and the this
will be set properly because you are calling a member function of lemon
.
The first argument to call
(or its friend apply
) is for the value of this
in the context of that function.
UPDATE
Dan, in the second example even without the change I made, that is if you still have lemon.thought = sayIt;
and you say alert(lemon.thought);
. You will still get the source of the function because you're not calling the function and passing its result to alert
. You're passing the function reference itself to alert
, and so it will print the source.
Upvotes: 3
Reputation: 1075755
Notes inline, discussion below, references and further reading at the end:
With parentheses when calling sayIt
function.
function Fruit(type){
this.type = type;
this.taste = "Awful";
// Here, you're *calling* the `sayIt` function and assigning its
// return value to `this.thought`. During the call, `this` will
// refer to the global object (not to the `Fruit` instance).
this.thought = sayIt();
}
function sayIt(){
// If this is called as it is above, `this` is the global object,
// which is `window` in browsers. Since `window` doesn't have
// `taste` or `type` properties, this returns "undefined undefined".
// That's what `this.thought` above receives.
return this.taste+" "+ this.type;
}
window.onload = function (){
var lemon= new Fruit("Lemon");
// You've said this alerts "undefined undefined", but I think you'll
// find it just alerts "undefined" (singular). There is no `sayIt`
// property on the `lemon` instance at all. If you alerted
// `lemon.thought` instead, you'd see the "undefined undefined" we
// stored there above.
alert(lemon.sayIt);
};
sayIt
function without parentheses.
function Fruit (type){
this.type = type;
this.taste = "Awful";
// Here you're assigning the `sayIt` function to `this.thought`.
// Perfectly normal stuff.
this.thought = sayIt;
}
function sayIt(){
return this.taste +" "+ this.type;
}
window.onload = function (){
var lemon= new Fruit("Lemon");
// Here you're also *referring* to the function object, not calling
// it. (To call a function, you use `()` after it.) So since functions
// are objects, you're passing an object reference into `alert`.
// Alert will try to convert that to a string, and the
// implementation of `toString` on `Function` objects in most
// environments is to dump out a version of the source code of
// the function (although this behavior is *not* standardized and
// some browsers, esp. mobile browsers, don't do it).
alert(lemon.thought);
};
Key concepts from the above:
Functions are objects. You call a function by using a reference to it followed by ()
, e.g.:
x = foo();
means "call foo
and assign its return value to x
".
You refer to the function object by just using its name, sans ()
, e.g.:
x = foo;
means "assign the function object foo
to x
. (You could then call it: x()
.)
Unlike some other languages, in JavaScript, this
is defined entirely by how a function is called, not where it's defined. When you call a function via a free variable (e.g., foo()
), you're doing nothing to explicitly set the this
for the function call, and so this
will be the default value, which is the global object (window
on browsers).
You can set what this
is in two different ways:
A. Put the function reference on an object property and call the function via the property's reference to it, e.g.:
// To put it on whatever `this` is at the moment:
this.thought = sayIt;
// Or to put it on an object we have in the variable `x`:
x.thought = sayIt;
You'd then call it via the property:
this.thought();
x.thought();
Within the function call, this
will refer to the object from which you retrieved the property.
B. Using the function object's intrinsic call
or apply
functions:
sayIt.call(lemon);
means "call the sayIt
function, making this
= lemon
within the function call." If you pass further arguments to call
, they'll be passed to the function, so:
sayIt.call(lemon, 1, 2, 3);
means "call sayIt
with this
= lemon
and pass in 1
, 2
, and 3
.
There's also the apply
function, which is just the same thing except you pass the arguments as an array rather than individually:
// note ------------v-------v---- the square brackets create an array
sayIt.applyl(lemon, [1, 2, 3]);
// More explicitly:
var a = [1, 2, 3];
sayIt.apply(lemon, a);
means "call sayIt
with this
= lemon
and pass in 1
, 2
, and 3
.
I've blogged a bit on these subjects, FWIW:
this
More to explore:
Upvotes: 4
Reputation: 340055
First code:
EDIT NB: edited to reflect edits in the question
function Fruit(type){
this.type = type;
this.taste = "Awful";
this.thought = sayIt(); // this line invokes sayIt, with global context,
// so sets thought to 'undefined undefined'
}
function sayIt() {
return this.taste+" "+ this.type; // as called, this == window, not the Fruit object
}
window.onload = function() {
var lemon= new Fruit("Lemon");
alert(lemon.thought); // see above
};
Second code:
function Fruit (type){
this.type = type;
this.taste = "Awful";
this.thought = sayIt;
}
function sayIt(){
return this.taste +" "+ this.type;
}
window.onload = function (){
var lemon= new Fruit("Lemon");
alert(lemon.thought); // doesn't -call- the function, results in .toString() on
// the function object
};
Upvotes: 2
Reputation: 181104
sayIt is not a function of the Fruit object - it's a function of the window object.
Fruit.thought is a function, or a "function pointer" as it is assigned to the window.sayIt function.
Upvotes: 0
Reputation: 22246
The function sayIt is defined after it is called. Moving the definition of sayIt above the definition of fruit would fix.
You're alerting the definition of a function and not the return value from calling that function.
Upvotes: 0
Reputation: 817208
I think you have a mistake in the first example. You wrote alert(lemon.sayIt);
where it should be alert(lemon.thought);
. Anyway...
With parentheses when calling
sayIt
function. This will alert "undefined undefined", why?
Because when you execute this.thought = sayIt();
, you are assigning the return value of sayIt
to this.thought
. When you call sayIt()
, then this
inside the function will refer to the global object which is window
is browser. And window.taste
and window.type
are not defined. Hence this.thought
will have string "undefined undefined"
assigned to it.
sayIt
function without parentheses. This will literally write down the function on the alert box, why?
In this case you are assigning a reference to the function itself to this.tought
. The string representation of a function is the code itself. Now you can call the function via lemon.tought()
. If you do so, this
will refer to the lemon
object and the output will be as expected.
So, call the function: alert(lemon.tought())
.
I suggest you read about
Upvotes: 1
Reputation: 7940
Based on your code, the "lemon" object has the properties "type", "taste", and "thought".
alert(lemon.sayIt);
This line alerts the value of the "sayIt" property on "lemon", converted to a String. Since the "lemon" object doesn't have a "sayIt" property, it converts the value undefined to a string and displays it.
alert(lemon.thought);
This line alerts the value of the "thought" property on "lemon", converted to a String. Since the "thought" property is a function, the string conversion displays the text of the function.
What you probably want to do is call the function, and display its return value: alert(lemon.thought());
Upvotes: 0