javascript中的动态函数名称?

IT技术 javascript function
2021-01-18 19:31:54

我有这个:

this.f = function instance(){};

我想要这个:

this.f = function ["instance:" + a](){};
6个回答

这基本上会在最简单的级别上完成:

"use strict";
var name = "foo";
var func = new Function(
     "return function " + name + "(){ alert('sweet!')}"
)();

//call it, to test it
func();

如果你想变得更花哨,我写了一篇关于“ JavaScript 中的动态函数名称”的文章

干得好!我刚刚自己发现了这一点,并准备将其发布在其中一个问题上,但您击败了我。我最近一直在使用backbone.js,并且厌倦了在我的chrome调试器中到处看到“孩子”。这解决了这个问题。我想知道是否有任何性能影响,例如使用 eval。
2021-03-18 19:31:54
AirBnB 强烈建议不要这样做,因为 Function 构造函数将用于eval评估 javascript - 从而使您的代码面临大量漏洞。
2021-03-21 19:31:54
是的,这适用于您需要即时构建某些东西的极端情况。
2021-03-28 19:31:54
老实说,我认为stackoverflow.com/a/40918734/2911851是一个更好的解决方案,不需要将函数主体作为字符串包含(除非我遗漏了一些东西,但我只是尝试过并且效果很好)。
2021-04-05 19:31:54
也存在安全隐患。我从 jsHint 得到“函数构造函数是 eval”,所以我将它包装在调试模式检查中,因为这是使用它的唯一原因。我想“使用严格”将防止对全局对象进行任何破坏,但是可以修改 Function 构造函数的任何参数,以及设置的任何“this”。
2021-04-07 19:31:54

您可以按照MDN JavaScript 参考中的说明使用 Object.defineProperty

var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
对谷歌浏览器常青树的相同评论。属性设置正确,但控制台中的名称是函数的原始名称。参见 2ality.com/2015/09 /... 好像函数名是创建时赋值的,不能改?
2021-03-14 19:31:54
在 2ality.com 页面上,请参阅下一段“更改函数名称”[1],它描述了在 MDN Javascript 参考中找到的相同技术。1. 2ality.com/2015/09/…
2021-03-24 19:31:54
在控制台中仍然相同:那是因为您看到的不是基于name而是基于与其一起存储的函数源代码- 您可以在调用fn.toString(). 你不能改变这一点。
2021-03-24 19:31:54
writable: false 没有必要,因为它一开始就已经是不可写的。
2021-04-02 19:31:54
看起来这会按预期设置 name 属性,但是如果我在浏览器(最新的 Firefox 开发版)中记录该功能,它会打印function fn()fn即原始名称。奇怪的。
2021-04-07 19:31:54

在最近的引擎中,你可以做

function nameFunction(name, body) {
  return {[name](...args) {return body(...args)}}[name]
}



const x = nameFunction("wonderful function", (p) => p*2)
console.log(x(9)) // => 18
console.log(x.name) // => "wonderful function"

虽然这在控制台和 node.js 中有效,但在转译时不起作用,在我的例子中是 typescript 3.6.2。
2021-03-30 19:31:54
虽然这确实有效,但我已经开始Object.defineProperty(func, 'name', {value: name})在我自己的代码中使用它,因为我认为它可能更自然和易于理解。
2021-04-02 19:31:54
回答我自己的问题:{[expr]: val}是一个对象初始值设定项(如 JSON 对象),其中expr有一些表达式;它的评估结果是关键。{myFn (..){..} }是 的简写{myFn: function myFn(..){..} }请注意,function myFn(..) {..}可以像匿名函数一样用作表达式,只有myFn一个名称。最后一个[name]只是访问对象的成员(就像obj.keyobj['key'])。...是展开运算符。(主要来源:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-04-03 19:31:54
在花了几个小时试图找出解决方案之后,我什至没想过使用具有计算属性名称的对象。正是我所需要的。谢谢!
2021-04-07 19:31:54
感谢您的解决!注意:这不会保留this. 例如obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();不会工作。您可以编辑您的答案并function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }改用!
2021-04-07 19:31:54

2021 年更新:CherryDT 的答案现在应该是最简单、最直接的方法,但它在堆栈跟踪或 Function.prototype.toString() 的不同浏览器中无法一致地工作,因此如果您需要,您会坚持使用这种不太方便的方法解决方案。

旧答案:通过使用 eval、hacky 解决方案或包装器,这里的许多建议都是次优的。自 ES2015 起,名称是从变量和属性的句法位置推断出来的。

所以这将工作得很好:

const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'

抵制创建命名函数工厂方法的诱惑,因为您将无法从外部传递函数并将其改造成句法位置以推断其名称。那么已经晚了。如果你真的需要它,你必须创建一个包装器。有人在这里这样做了,但该解决方案不适用于类(也是函数)。

这里已经写了一个更深入的所有变体的答案:https : //stackoverflow.com/a/9479081/633921

@CherryDT 抱歉,我不得不回过头来重新审视一些旧的用例以了解问题所在。Object.defineProperty在很长一段时间内,部分缺乏对 Safari 的支持(由于与硬件一起提供,Safari 浏览器版本比大多数浏览器的存活时间更长),但主要是它不能始终如一地用于堆栈跟踪和Function.prototype.toString. 使用您的解决方案,尝试此操作const fn1 = nameFunction('fn2', function fn3(){ throw new Error("whoops") }); fn1();并检查 Firefox 与 Chrome 中的堆栈跟踪(如果您删除 fn3,它们的行为仍然不同)。
2021-03-12 19:31:54
@d4nyll 我已经回答了:它创建了一个包装器,它破坏了有状态的函数(使用“this”的函数)又名类。
2021-03-22 19:31:54
这个答案如何改进stackoverflow.com/a/41854075/3966682
2021-03-29 19:31:54
@Albin FWIW,我完全不清楚你的回答是如何说的。无论哪种方式,这是很好的知道。
2021-04-05 19:31:54
@JasonYoung“抵制创建命名函数工厂方法的诱惑,因为您将无法从外部传递函数并将其改造成句法位置以推断其名称。那么已经太晚了。如果你真的需要那个,你必须创建一个包装器。有人在这里这样做了,但该解决方案不适用于类(它们也是函数)。”
2021-04-05 19:31:54

更新

正如其他人提到的,这不是最快也不是最推荐的解决方案。Marcosc 下面的解决方案是要走的路。

您可以使用评估:

var code = "this.f = function " + instance + "() {...}";
eval(code);
@Tom 对于未来的读者:这个解决方案与 Marcosc 的答案并没有什么不同,他们都使用eval()Function构造函数在里面这样做)。
2021-03-15 19:31:54
这就是我要求的,谢谢!(反正我不会使用这个功能,因为它太慢了)
2021-03-17 19:31:54
@sg3s:你能提出另一个解决方案吗?
2021-03-25 19:31:54
我知道这是 OP 要求的,但这是一个可怕的想法。仅仅因为你可以并不意味着你应该做这样的事情。有更好的替代方案,它们在功能方面几乎完全相同。
2021-04-03 19:31:54
@sg3s:感谢您回答我的评论!让我解释一下我的意思,以及我真正想问的问题:Marcosc 的解决方案真的与 eval 有很大不同吗?如果您评估某些内容或将其提供给 Function 构造函数,它真的会有所不同吗?如果是这样,您能解释一下差异及其后果吗?谢谢!
2021-04-08 19:31:54