setTimeout with arguments

If you don't want to declare a separate function, you can use an immediately invoked function expression and closure, e.g.

// Parameter to use
var bar = 'bar';

// Function to call
function foo(arg) {
  alert(arg);
}

// Go…
setTimeout(
  (function(arg1){
    return function(){
      foo(arg1);
    };
  }(bar)), 2000);

Alternatively, you can use the function constructor:

setTimeout( Function('foo(bar)'), 2000);

Or you can use a string:

setTimeout('foo(bar)', 1000);

which is essentially the same thing. Now wait for howls of "but that's like using eval, and everyone knows eval is evil and a massive security breach — all your firstborn are doomed!"

But seriously, eval (and the Function constructor) are inefficient and can lead to lazy programming, so use another option, such as the first above.


It appears the ability has been added to some browsers pass parameters to setTimeout:

syntax: setTimeout (function (p1,p2) {},1000,p1,p2); (add as many params as you want)

If you want to ensure it works everywhere, you can use the attached code.

Note: If you want to set a timeout immediately after installing it, it's best to use the callback parameter and do it in there

for example

installSwizzledTimeout(function(param1,param2){
    setTimeout(myFunc,200,param1,param2);},param1,param2);
}

This is because it uses a trick to detect if it is needed, by setting a very short timeout and counting the parameters.

window.swizzledSetTimeout = function (fn, ms) {
    if (arguments.length === 2) {
        //console.log("Bypassing swizzledSetTimeout");
        return window.originalSetTimeout(fn, ms);
    } else {
        var args = [];
        for (i = 2; i < arguments.length; i++) {
            args.push(arguments[i])
        };
        //console.log("Setting swizzledSetTimeout for function (",args,") {...} in ",ms," msec");
        var retval = window.originalSetTimeout(function () {
            //console.log("Invoking swizzledSetTimeout for function (",args,") {...}");
            fn.apply(null, args);
        }, ms);
        return retval;
    }
}

function installSwizzledTimeout(cb) {
    var args = [];
    for (i = 1; i < arguments.length; i++) {
        args.push(arguments[i])
    };
    setTimeout(function (arg) {
        //console.log("arguments.length:",arguments.length,window.setTimeout.toString());
        if (arguments.length == 0) {

            function doInstall() {
                //console.log("Installing new setTimeout");
                window.originalSetTimeout = window.setTimeout;
                window.setTimeout = function setTimeout() {
                    return window.swizzledSetTimeout.apply(null, arguments);
                };
                if (cb) {
                    cb.apply(null, args);
                };
            }

            if (window.setTimeout.toString().indexOf("swizzledSetTimeout") < 0) {
                doInstall();
            }
        } else {
            //console.log("existing set time supports arguments ");
            if (cb) {
                cb.apply(null, args);
            };
        }
    }, 0, 1, 2, 3, 4);
}

You can pass it an anonymous function that invokes makeTimeout with the given arguments:

setTimeout(function () {
  makeTimeout(sp.name);
}, 250);

There's also an alternative, using bind:

setTimeout(makeTimeout.bind(this, sp.name), 250);

This function, however, is an ECMAScript 5th Edition feature, not yet supported in all major browsers. For compatibility, you can include bind's source, which is available at MDN, allowing you to use it in browsers that don't support it natively.

DEMO.

Tags:

Javascript