Use eval
. eval
is evil when you can avoid it, but with strings you're in total control of, in a scope you control, with an understanding of the costs (you're firing up a JavaScript parser), to do something you cannot do otherwise (as in this case), it's fine provided you really need to do that thing. But if you're not in control of the string or scope, or you don't want the cost, you'll have to live with an anonymous function.
Here's how the eval
option looks:
var name = ;
var f = eval(
"(function() {\n" +
" function " + name + "() {\n" +
" console.log('Hi');\n" +
" }\n" +
" return " + name + ";\n" +
"})();"
);
Live example | Live source
That creates a function with the name we come up with at runtime without leaking the name into the containing scope (and without triggering the flawed handling of named function expressions in IE8 and earlier), assigning a reference to that function to f
. (And it formats the code nicely so single-stepping through it in a debugger is easy.)
This didn't used to correctly assign the name (surprisingly) in older versions of Firefox. As of the current version of their JavaScript engine in Firefox 29, it does.
Because that uses eval
, the function you create has access to the scope in which it was created, which is important if you're a tidy coder who avoids global symbols. So this works, for instance:
(function() {
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
var name = ;
var f = eval(
"(function() {\n" +
" function " + name + "() {\n" +
" display('Hi');\n" +
" }\n" +
" return " + name + ";\n" +
"})();"
);
})();
Use the Function
constructor, as demonstrated in this article by Marcos Cáceres:
var f = new Function(
"return function " + name + "() {\n" +
" display('Hi!');\n" +
" debugger;\n" +
"};"
)();
Live example | Live source
There we create a temporary anonymous function (the one created via the Function
constructor) and call it; that temporary anonymous function creates a named function using a named function expression. That will trigger the flawed handle of named function expressions in IE8 and earlier, but it doesn't matter, because the side-effects of that are limited to the temporary function.
This is shorter than the eval
version, but has an issue: Functions created via the Function
constructor do not have access to the scope in which they were created. So the example above using display
would fail, because display
wouldn't be in-scope for the created function. (Here's an example of it failing. Source). So not an option for tidy coders avoiding global symbols, but useful for those times when you want to disassociate the generated function from the scope in which you're generating it.
new Function
函数一个真实的名称,2. 你可以通过将eval
包装在try/catch
块中来捕获语法错误,就像使用new Function
一样。在这方面没有区别。 - T.J. Crowdereval
和new Function
,我建议使用function replaceHere(){...}.toString()
而不是多行字符串。我还见过它被用在一个用户脚本中,通过创建一个新的脚本元素将其注入到页面中。 - John Dvorak