有没有非eval的方式来创build一个运行时确定的名字的函数?

有没有什么办法可以创build一个真正的名字 ,在运行时确定的eval ,而不使用eval ,只使用纯JavaScript? (因此,没有生成script元素,因为这些元素是特定于浏览器环境的[在许多方面总是会变相评价];不使用某个特定JavaScript引擎的非标准function等)

请注意,我特别不会询问具有名称的variables或属性引用的匿名函数,例如:

 // NOT this var name = /* ...come up with the name... */; var obj = {}; obj[name] = function() { /* ... */ }; 

在那里,虽然对象属性有一个名字,但函数没有。 匿名函数适用于很多事情,但不是我在这里寻找的东西。 我希望函数有一个名称(例如,在debugging器中的调用堆栈中显示等)。

ECMAScript 2015的答案(又名“ES6”)

是的 。 从ES2015开始,由分配给对象属性的匿名函数expression式创build的函数将使用该对象属性的名称。 当我在2015年5月11日写这篇文章的时候,除了微软的Windows 10 Preview的“Project Spartan”之外,没有任何其他的JavaScript引擎支持这个function(是的,你读得对,M $在Mozilla 或者 Google之前就已经到了)规范和实现将迎头赶上。 更新 :截至2016年10月,Chrome的最新版本实现了Function#name和各种分配名称的规则; Firefox仍然没有,但他们会到达那里。

例如,在ES2015中,这将创build一个名为“foo ###”的函数,其中###是1-3位数字:

 const dynamicName = "foo" + Math.floor(Math.random() * 1000); const obj = { [dynamicName]() { throw new Error(); } }; const f = obj[dynamicName]; // See its `name` property (Edge and Chrome for now, eventually Firefox will get it) console.log("Function's `name` property: " + f.name + " (see compatibility note)"); // We can see that it truly has a name (even in Firefox which doesn't have the `name` property yet) via an exception: try { f(); } catch (e) { console.log(e.stack); } 

这是我前段时间提出的效用函数。 它使用了@TJCrowder伟大的答案中概述的Function构造函数技术,但改进了它的缺点,并允许对新函数的范围进行细化控制。

 function NamedFunction(name, args, body, scope, values) { if (typeof args == "string") values = scope, scope = body, body = args, args = []; if (!Array.isArray(scope) || !Array.isArray(values)) { if (typeof scope == "object") { var keys = Object.keys(scope); values = keys.map(function(p) { return scope[p]; }); scope = keys; } else { values = []; scope = []; } } return Function(scope, "function "+name+"("+args.join(", ")+") {\n"+body+"\n}\nreturn "+name+";").apply(null, values); }; 

它可以让你整洁, 避免通过eval完全访问你的范围,例如在上面的情况:

 var f = NamedFunction("fancyname", ["hi"], "display(hi);", {display:display}); f.toString(); // "function fancyname(hi) { // display(hi); // }" f("Hi");