A safe way to do is to sandbox the alleged function while testing its type:
function isFunction(expr) {
function sandboxTemplate() {
var window, document, alert; // etc.
try {
return typeof $expr$ == "function";
} catch (e) {
return false;
}
}
try {
var sandbox = new Function(
sandboxTemplate.toString().replace("$expr$", expr)
+ "return sandboxTemplate()");
return sandbox();
} catch (e) {
return false;
}
}
function test(expr) {
document.write("<div>\"" + expr + "\" <b>is "
+ (isFunction(expr) ? "" : "not ")
+ "</b>a function</div>");
}
/* Let's do some testing */
function realFunction() {
}
test("realFunction"); // exists!
test("notHere"); // non-existent
test("alert('Malicious')"); // attempt to execute malicious code!
test("syntax error {"); // attempt to blow us up!
The output:
- "realFunction" is a function
- "notHere" is not a function
- "alert('Malicious')" is not a function
- "syntax error {" is not a function
The sandboxing code could be written in a more concise manner but I like using "template" functions instead of embedding JS code as string literals.
And oh, this does it nicely without using eval
-- though one can argue that using a Function constructor is no different than an eval
.