javascript中的动态函数名称?

Tot*_*.js 77 javascript function

我有这个:

this.f = function instance(){};
Run Code Online (Sandbox Code Playgroud)

我想要这个:

this.f = function ["instance:" + a](){};
Run Code Online (Sandbox Code Playgroud)

Mar*_*osc 111

这基本上是在最简单的层面上做到的:

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

//call it, to test it
func();
Run Code Online (Sandbox Code Playgroud)

如果你想获得更多的幻想,我写了一篇关于" JavaScript中的动态函数名称 "的文章.

  • 老实说,我认为 /sf/answers/2864311411/ 是更好的解决方案,无需将函数主体作为字符串包含(除非我遗漏了一些东西,但我只是尝试过并且效果很好)。 (2认同)
  • [AirBnB强烈建议不要这样做](https://github.com/airbnb/javascript#functions--constructor),因为Function构造函数将使用`eval`来评估javascript-从而使您的代码面临许多漏洞。 (2认同)

Dar*_*ren 32

您可以使用MDN JavaScript Reference [1]中提到的Object.defineProperty:

var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
Run Code Online (Sandbox Code Playgroud)
  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Description

  • 看起来这会按预期设置 name 属性,但是如果我在浏览器(最新的 Firefox 开发版)中记录该函数,它会打印 `function fn()`,`fn` 是原始名称。奇怪的。 (3认同)

kyb*_*kos 25

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

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"
Run Code Online (Sandbox Code Playgroud)

  • 虽然这确实有效,但我已经开始在我自己的代码中使用`Object.defineProperty(func,'name',{value:name})`,因为我认为它可能更自然和可理解. (6认同)
  • 在花了数小时试图找出解决方案之后,我什至没想过使用具有计算属性名称的对象。正是我需要的。谢谢! (2认同)
  • 这对我有用!但我无法理解语法;你能解释一下吗?我相信我理解了这一切,除了 `[name]` 的两种用法,以及 `return` 创建一个没有 `function` 关键字的函数这一事实。 (2认同)
  • 回答我自己的问题:`{[expr]:val}`是一个对象初始值设定项(与JSON对象一样),其中`expr`是某种表达式;评估结果是关键。{myFn(..){..}}}是{{myFn:function myFn(..){..}}}的简写。请注意,`函数myFn(..){..}`可以用作表达式,就像匿名函数一样,只有`myFn`具有名称。最后的[name]只是访问对象的成员(就像obj.key或obj ['key']`一样)。`...`是点差运算符。(主要来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer) (2认同)
  • 感谢您的解决方案!注意:这不会保留“this”的值。例如 `obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('名称',obj.getX); obj.getX();` 不起作用。您可以编辑答案并使用 `function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }` 代替! (2认同)
  • 虽然这在控制台和 node.js 中有效,但在转译时不起作用,在我的情况下使用 typescript 3.6.2。 (2认同)

Alb*_*bin 10

我认为通过使用eval,hacky解决方案或包装器,这里的大多数建议都不是最理想的.从ES2015开始,名称是从变量和属性的句法位置推断出来的.

所以这将工作得很好:

const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
Run Code Online (Sandbox Code Playgroud)

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

所有变体的更深入的答案都写在这里:https://stackoverflow.com/a/9479081/633921


Mo *_*our 7

更新

正如其他人提到的那样,这不是最快也不推荐的解决方案。Marcosc下面的解决方案解决之道

您可以使用eval:

var code = "this.f = function " + instance + "() {...}";
eval(code);
Run Code Online (Sandbox Code Playgroud)

  • @Tom对于未来的读者:这个解决方案与Marcosc的答案并没有什么不同,它们都使用`eval()`(`Function`构造函数在内部完成)。 (5认同)
  • @ sg3s:您可以提出其他解决方案吗? (4认同)
  • 我知道这是OP的要求,但这是一个可怕的想法。仅仅因为您可以做并不意味着您应该做这样的事情。在功能上几乎有完全相同的更好的替代方法。 (3认同)
  • @ sg3s:感谢您回答我的评论!让我解释一下我的意思,以及我实际上要问的问题:Marcosc的解决方案与eval确实有很大不同吗?如果您评估或将其提供给Function构造函数,是否真的有所不同?如果是这样,您能解释一下差异及其后果吗?谢谢! (2认同)

Che*_*yDT 5

默认情况下,该函数的name属性不是writeable,但由于它是,configurable我们仍然可以使用Object.defineProperty它来更改它。由于Object.defineProperty方便地返回对象本身,我们可以编写一个具有动态名称的函数,如下所示:

const theName = 'foobar'

const fn = Object.defineProperty(function () {
  /* ... */
}, 'name', { value: theName })

console.log(fn.name) // Logs foobar
Run Code Online (Sandbox Code Playgroud)

当然,这可以分解为辅助函数:

const nameFunction = (name, fn) => Object.defineProperty(fn, 'name', { value: name })

const fn = nameFunction('foobar', function () {
  /* ... */
})

console.log(fn.name) // Logs foobar
Run Code Online (Sandbox Code Playgroud)

当然,上面的nameFunction函数也可以用于重命名现有函数(这里只是重命名并返回匿名函数)。