Difference between setTimeout with a string argument and with a non-string argument
Categories:
setTimeout: String vs. Function Arguments in JavaScript

Explore the critical differences and implications of using string versus function arguments with JavaScript's setTimeout
for robust and secure asynchronous operations.
The setTimeout
function in JavaScript is a fundamental tool for scheduling code execution after a specified delay. While commonly used with a function as its first argument, it also supports passing a string of code. This article delves into the distinctions between these two approaches, highlighting their performance, security, and best practice implications.
Understanding setTimeout
with a Function Argument
The most common and recommended way to use setTimeout
is by providing a function (either an anonymous function, an arrow function, or a reference to a named function) as its first argument. This approach directly executes the provided function after the delay, operating within the current scope and closure.
function greet() {
console.log('Hello from a named function!');
}
setTimeout(greet, 1000); // Using a named function
setTimeout(function() {
console.log('Hello from an anonymous function!');
}, 2000); // Using an anonymous function
setTimeout(() => {
console.log('Hello from an arrow function!');
}, 3000); // Using an arrow function
Examples of setTimeout
using function arguments.
setTimeout
is generally preferred because it offers better performance, security, and maintainability. It avoids the overhead of parsing and evaluating a string of code.Understanding setTimeout
with a String Argument
Less commonly, setTimeout
can accept a string as its first argument. When a string is passed, JavaScript internally uses eval()
to parse and execute the string as code. This behavior has significant implications for both performance and security.
let message = 'World';
setTimeout("console.log('Hello ' + message + '!');", 1000); // Using a string argument
Example of setTimeout
using a string argument.
setTimeout
unless absolutely necessary. It's a potential security vulnerability (cross-site scripting - XSS) and can lead to performance issues due to the eval()
overhead.Key Differences and Implications
The choice between a string and a function argument for setTimeout
is not merely stylistic; it has profound effects on how your code behaves, its security posture, and its efficiency.
flowchart TD A[setTimeout Call] --> B{First Argument Type?} B --"Function (e.g., `() => {}`)"--> C[Direct Execution] C --> D[Accesses current scope/closures] C --> E[Optimal Performance] C --> F[Secure] B --"String (e.g., `'alert("Hi")'`)"--> G[Internal `eval()` Call] G --> H[Executes in global scope] H --> I[Performance Overhead] H --> J[Security Risk (XSS)] J --> K[Avoid if possible]
Comparison of setTimeout
behavior with function vs. string arguments.
Performance
When setTimeout
receives a function, it simply schedules that function for execution. When it receives a string, it must first parse and evaluate that string as JavaScript code, which is a more resource-intensive operation. This overhead can be negligible for a single call but can accumulate in applications with frequent setTimeout
calls.
Security
This is arguably the most critical difference. Using a string argument is akin to using eval()
. If the string content originates from user input or an untrusted source, it creates a severe Cross-Site Scripting (XSS) vulnerability. Malicious code injected into the string could be executed with the same privileges as your application, leading to data theft, session hijacking, or defacement.
Scope and Closures
Functions passed to setTimeout
retain their original scope and closures. This means they can access variables defined in their outer lexical environment. String arguments, however, are evaluated in the global scope. They cannot directly access local variables or closures from where setTimeout
was called, which can lead to unexpected behavior or ReferenceError
s if not handled carefully.
function createTimer(name) {
let count = 0;
setTimeout(function() {
count++;
console.log(`${name} count: ${count}`); // Accesses 'name' and 'count' from closure
}, 100);
// This would fail if 'count' was accessed from a string argument
// setTimeout("console.log('Count: ' + count);", 200); // ReferenceError: count is not defined
}
createTimer('My Timer');
Demonstrating scope and closure access with function arguments.
When to Use (and Avoid) String Arguments
In modern JavaScript development, there are almost no legitimate reasons to use a string argument with setTimeout
. Any scenario where you might consider it can be better handled with a function argument, often by creating a closure or using bind()
to pass arguments.
Historically, string arguments might have been used in very specific, controlled environments or for extremely simple, static operations. However, given the security risks and performance implications, it's a practice that should be actively avoided.
setTimeout
, use an anonymous function wrapper or Function.prototype.bind()
instead of a string. For example: setTimeout(() => myFunction(arg1, arg2), delay)
or setTimeout(myFunction.bind(null, arg1, arg2), delay)
.