关于javascript:命名匿名函数

Naming an anonymous function

有可能以某种方式为匿名函数设置名称吗?

没有必要为匿名函数添加函数名称到命名空间,但我想避免在我的javascript调试器中看到大量(?),这样我就可以保持调用堆栈跟踪信息。

我也可以安全地将正常声明的函数作为参数而不是匿名函数传递,或者我会遇到一些奇怪的错误。 它似乎工作。

1
2
3
$("object").bind("click", function() { alert("x"); });

$("object").bind("click", function debuggingName() { alert("x"); });

[编辑]

我的意思是喜欢的东西

1
$("object").bind("click", function() { Function.Name ="debuggingName"; alert("x"); });


你的第二个例子是使用一个命名的函数表达式,它在大多数浏览器中都能正常工作,但在使用它之前你应该注意IE中的一些问题。我建议阅读kangax关于这个主题的优秀文章。


您可以使用箭头功能执行此类操作,它适用于Node。

1
2
3
4
5
6
7
8
9
10
const createTask = ([name, type = 'default']) => {
  const fn = () => { ... }

  Object.defineProperty(fn, 'name', {
    value: name,
    configurable: true,
  })

  return fn
}

MDN在这里有点误导:

You cannot change the name of a function, this property is read-only...

To change it, you could use Object.defineProperty() though.

这个答案提供了更多细节。


使用ECMAScript2015(ES2015,ES6)语言规范,可以不使用慢速和不安全的eval函数,也可以不使用Object.defineProperty方法,它既破坏了函数对象,又无论如何都无法在某些关键方面起作用。

例如,请参阅此nameAndSelfBind函数,该函数既可以命名匿名函数又可以重命名命名函数,也可以将自己的实体绑定到自身,并存储对要在外部作用域中使用的已处理函数的引用(JSFiddle) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
(function()
{
  // an optional constant to store references to all named and bound functions:
  const arrayOfFormerlyAnonymousFunctions = [],
        removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout

  // this function both names argument function and makes it self-aware,
  // binding it to itself; useful e.g. for event listeners which then will be able
  // self-remove from within an anonymous functions they use as callbacks:
  function nameAndSelfBind(functionToNameAndSelfBind,
                           name = 'namedAndBoundFunction', // optional
                           outerScopeReference)            // optional
  {
    const functionAsObject = {
                                [name]()
                                {
                                  return binder(...arguments);
                                }
                             },
          namedAndBoundFunction = functionAsObject[name];

    // if no arbitrary-naming functionality is required, then the constants above are
    // not needed, and the following function should be just"var namedAndBoundFunction =":
    var binder = function()
    {
      return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
    }

    // this optional functionality allows to assign the function to a outer scope variable
    // if can not be done otherwise; useful for example for the ability to remove event
    // listeners from the outer scope:
    if (typeof outerScopeReference !== 'undefined')
    {
      if (outerScopeReference instanceof Array)
      {
        outerScopeReference.push(namedAndBoundFunction);
      }
      else
      {
        outerScopeReference = namedAndBoundFunction;
      }
    }
    return namedAndBoundFunction;
  }

  // removeEventListener callback can not remove the listener if the callback is an anonymous
  // function, but thanks to the nameAndSelfBind function it is now possible; this listener
  // removes itself right after the first time being triggered:
  document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
  {
    e.target.removeEventListener('visibilitychange', this, false);
    console.log('
Event listener 1 triggered:'
, e, '
this: '
, this,
                '

removeEventListener 1 was called; if"this" value was correct,"'

                + e.type + '"" event will not listened to any more');
  }, undefined, arrayOfFormerlyAnonymousFunctions), false);

  // to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
  // name -- belong to different scopes and hence removing one does not mean removing another,
  // a different event listener is added:
  document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
  {
    console.log('
Event listener 2 triggered:'
, e, '
this: '
, this);
  }, undefined, arrayOfFormerlyAnonymousFunctions), false);

  // to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
  // formerly anonymous callback function of one of the event listeners, an attempt to remove
  // it is made:
  setTimeout(function(delay)
  {
    document.removeEventListener('visibilitychange',
             arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
             false);
    console.log('
After '
+ delay + 'ms, an event listener 2 was removed;  if reference in '
                + 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
                + 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
  }, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();

如果动态函数名称是问题。你可以试试这个:

1
2
3
4
5
6
function renameFunction(name, fn) {
    return (new Function("return function (call) { return function" + name +
      " () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
}

renameFunction('dynamicName',function() { debugger })();

来源:Nate Ferrero


我通常这样做:
$("对象")。绑定("点击"
,function name(){
警报("X");
});

并且不要遇到任何问题。

在一些主要的图书馆鼓励这样做:

https://groups.google.com/forum/m/#!topic/firebug/MgnlqZ1bzX8

http://blog.getfirebug.com/2011/04/28/naming-anonymous-javascript-functions/


匿名函数是没有名称的函数,它从定义的位置执行。或者,您可以在使用之前定义调试功能。

1
2
3
4
5
function debuggingName() {
    alert("x");
}

$("object").bind("click", debuggingName);