2

i am getting undefined undefined when i defined and call the setTimeout function as follow:

var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        console.log(this.first + ' ' + this.last);
    }
}

setTimeout(person.getName(), 2000);

unless if i wrap the person.getName() in a function as follow:

setTimeout(function(){
    person.getName()
}, 2000);

Now i am getting a right output. Why it's so?

2
  • Did you call the settimout function before you initialize person Commented May 30, 2013 at 1:12
  • Actually your first example works and puts joe doe, but doesn't wait for the timeout… Commented May 30, 2013 at 1:20

6 Answers 6

3

Assuming you meant:

var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        console.log(this.first + ' ' + this.last);
    }
}

setTimeout(person.getName, 2000);

The reason you get undefined is that what you are effectively doing is :

var somefunc = person.getName; 
setTimeout(somefunc, 2000);

So somefunc gets called in the context of window. i.e. window.somefunc()

However when you do

setTimeout(function(){
    person.getName()
}, 2000);

The context of getName is preserved as you are Calling (not passing around) person.getName

Sign up to request clarification or add additional context in comments.

1 Comment

What he's effectively doing is var somefunc = person.getName();, which sets somefunc() to whatever person.getName() returns. Context is not the problem, the issue is calling versus referring.
1

I have just answerd for something similar here :

How can I pass a parameter to a setTimeout() callback?

The setTimeout function fix the context to the window, so it's not possible to do what you want !

To do it i have wrapped the setTimeout function in another one which can set the context :

myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
            var _deepResultFunction = function _deepResultFunction(){
                //_deepFunction(_deepData);
                _deepFunction.apply(  _deepCtxt , _deepData);
            };
        return _deepResultFunction;
    })(fn , params , ctxt)
, _time) 
};

// lets try this functions :
for(var i=0; i<10; i++){
   setTimeout(function(){console.log(i)} ,1000 ); // stock setTiemout in closure
}

for(var i=0; i<10; i++){
   setTimeout( console.log(i) ,1000 ); // stock setTiemout direct call 
}

for(var i=0; i<10; i++){
   setTimeout(console.log ,1000 , i); // stock setTiemout not compatible IE
}

for(var i=0; i<10; i++){
   myNass_setTimeOut(console.log ,1000 , [i] , console); // wrapped setTimeout
}

So to answer your question :

var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        console.log(this.first + ' ' + this.last);
    }
}

setTimeout(person.getName(), 2000);

When you launch : setTimeout(person.getName(), 2000); setTimeout will execute in the future 2s (2000ms) the 1st argument !

But what is the value of your 1st argument ? : the result of your function person.getName( ), so it's equivalent of :

var _arg1 = person.getName();
setTimeout(_arg1 , 2000);

which is very different of :

var _arg1 = person.getName;
setTimeout(_arg1 , 2000);

The first case you pass the result of a function to setTimeout which wait a reference to a function. In the second case you pass a reference to a function (good it's what expected), but not in the good context !

So, now you have to fix the context : whith the core javascript function :apply

Now try this :

var _arg1 = function(){ person.getName.apply(person) };
setTimeout(_arg1 , 2000);
myNass_setTimeOut(person.getName , 2000 , null , person);

So you have two choice :

  • Fixing the context for every argument you pass to setTimeout.
  • Use a function which do it for you

the myNass_setTimeOut function will make the trick !

Now, let see something a little bit more deeper :

var person = {
        first: 'joe',
        last: 'doe',
        getName: function(){
            console.log(this.first + ' ' + this.last);
        } ,
        say : function(sentence){
             console.log(this.first + ' ' + this.last + ' say : ' + sentence)
        }
    }

How could pass argument sentence to a setTimeout ?

var heSay = "hello !"; setTimeout(person.say(heSay) , 1000 ); heSay = "goodBye !";
// not good : execute immediatly

var heSay = "hello !";setTimeout(function(){person.say(heSay)} , 1000 ); heSay = "goodBye !";
// not good : hesay googbye

var heSay = "hello !"; setTimeout(person.say , 1000 , heSay); heSay = "goodBye !";
// not good bad context

var heSay = "hello !"; setTimeout(function(whatHeSay){person.say(whatHeSay)} , 1000 , heSay);heSay = "goodBye !";
// GOOD ! ok but not compatible with IE

var heSay = "hello !"; myNass_setTimeOut(person.say , 1000 , [heSay] , person ); heSay = "goodBye !";
// just good !

hope this help you !

edit :

for modern browser suporting bind don't take care about that do what say here @dandavis

Comments

0
  1. you call it too early.
  2. the this gets broken when you save a function ref without the object it's attached to.

solution?

use bind and don't call it early:

var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        console.log(this.first + ' ' + this.last);
    }
}

setTimeout(person.getName.bind(person), 2000);

Comments

0
var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        console.log(this);
    }
}
person.getName()
setTimeout(person.getName, 2000);

Outputs:

Object {first: "joe", last: "doe", getName: function}
Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

My guess is, JavaScript pulls the getName function out of the scope of person

4 Comments

Also, note that setTimeout(person.getName, 2000); is different to setTimeout(person.getName(), 2000);
person is not a scope. It's the context of the call person.getName(), and also that function never was "in" there to be "pulled out"
en.wikipedia.org/wiki/Scope_(computer_science) Well actually, scope == context, so I'd still be correct
0

Your first function works fine for me (tested in Chrome):

http://jsfiddle.net/fzrxK/1/

var person = {
    first: 'joe',
    last: 'doe',
    getName: function(){
        alert(this.first + ' ' + this.last);
    }
}

setTimeout(person.getName(), 2000);

Perhaps there's another issue elsewhere?

2 Comments

I updated the code for an 'alert' instead of console.log - still seems to work fine for me both ways...
Ahh - I understand you now. Seems there was more than one error in the original code.
0

Calling person.getName() executes the function and returns undefined (as nothing was declared to return in that function).

What you wanted was:

setTimeout(person.getName, 2000);

Calling setTimeout(person.getName(), 2000); sets a timeout to execute the results returned by person.getName() which is undefined rather than a function.

Calling setTimeout(person.getName, 2000); sets a timeout to execute the function person.getName.

With parenthesis executes the function. Without parenthesis passes the variable (which happens to be defined as a function).

Edit: As @Isaac points out, passing the function person.getName in also changes the behavior of this so that is likely not what you wanted either.

1 Comment

setTimeout(person.getName, 2000) is what he actually did, otherwise he wouldn't have got the undefined undefined output in console…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.