2012-09-17 17 views
11

avendo un po 'di mal di testa nel tentativo di risolvere questo problema. Quello che voglio fare è avere un setTimeout personalizzato con argomenti senza il che deve creare una funzione per passarlo. Mi spiego per codice:setTimeout con argomenti

vuole evitare:

function makeTimeout(serial){ 
    serial.close(); 
} 

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

quello che voglio fare è in qualche modo solo chiamare un 1 nave da come:

setTimeout(function(arg1){ .... }(argument_value), 250); 

si può fare o puoi passare solo in una funzione senza argomento?

risposta

22

È possibile passare una funzione anonima che richiama makeTimeout con gli argomenti dati:

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

C'è anche un'alternativa, utilizzando bind:

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

Questa funzione, però, è un 5 ° ECMAScript Funzionalità dell'edizione, non ancora supportata in tutti i principali browser. Per compatibilità, puoi includere di bind, che è disponibile su MDN, permettendoti di usarlo nei browser che non lo supportano in modo nativo.

DEMO.

+4

Si segnala che il valore passato a 'makeTimeout' sarà il valore di' sp.name' quando viene chiamata la funzione, che potrebbe essere diverso per il valore che aveva quando 'setTImeout' è stato chiamato. – RobG

+0

Secondo http://kangax.github.io/es5-compat-table/#Function.prototype.bind, il binding è ora supportato dai principali browser. –

+0

Come ha detto RobG, per fare in modo che questa cosa funzioni al 100% è necessario utilizzare una chiusura https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures Nel momento in cui scade il timeout, il valore 'sp.name' potrebbe essere cambiato. – ikromm

4

Se non si desidera dichiarare una funzione separata, è possibile utilizzare un'espressione e una chiusura della funzione immediatamente richiamate, ad es.

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

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

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

In alternativa, è possibile utilizzare la funzione di costruzione:

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

Oppure si può utilizzare una stringa:

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

che è essenzialmente la stessa cosa. Ora aspetta per ululati di "ma questo è come l'utilizzo di eval, e tutti sanno eval è male e una massiccia violazione della sicurezza - tutti i vostri primogeniti sono condannati"

Ma seriamente, eval (e il costruttore Funzione) sono inefficienti e può portare a programmazione pigra, quindi usa un'altra opzione, come la prima sopra.

2

Sembra la capacità è stato aggiunto a alcuni browser passare parametri a setTimeout:

sintassi:setTimeout (function (p1,p2) {},1000,p1,p2);(aggiungere quante params come volete)

Se si vuole garantire funziona ovunque, puoi usare il codice allegato.

Nota: Se si desidera impostare un timeout subito dopo l'installazione, è meglio utilizzare il parametro di callback e lo fa in là

ad esempio

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

Questo perché usa un trucco per rilevare se è necessario, impostando un timeout molto breve e contando i parametri.

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); 
}