29

Is it possible to somehow set a name for anonymous functions?

There is no need to add function names to the namespace for anonymous functions but I would like to avoid seeing a large amount of (?) in my javascript debugger so I can keep the call stack trace informative.

Also can I safely pass normal declared functions as arguments instead of anonymous functions or will I walk into some strange errors. It seems to work.

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

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

[Edit]

I meant something along the likes of

$("object").bind("click", function() { Function.Name = "debuggingName"; alert("x"); });
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 4
    @Raynos - a named anonymous function is a contradiction in terms!! – Jagmag Oct 04 '10 at 10:00
  • Are you getting some error when you use your second construct above? – Sachin Shanbhag Oct 04 '10 at 10:00
  • I just want to set something within an anonymous function that the debugger can pick up and display as a useful debugging function name. I want to use them exactly as I would use anonymous functions – Raynos Oct 04 '10 at 10:27
  • @raynos: have you tried $("object").bind("click", function MY_NOT_SO_ANONYMOUS_FUNCTION_NAME () { alert("x"); }); – some Oct 04 '10 at 12:17
  • @some how is that any different from the second example I have? Yes I have. it's probably the best way to handle it. – Raynos Oct 04 '10 at 13:22
  • 1
    @Raynos: Sorry, I must have missed that you already wrote that. It's exactly the same as your second example. – some Oct 04 '10 at 13:40

6 Answers6

21

Your second example is using a named function expression, which works fine in most browsers but has some problems in IE that you should be aware of before using it. I recommend reading kangax's excellent article on this subject.

Ron Burk
  • 6,058
  • 1
  • 18
  • 20
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Thank you, I was worried that passing a named function expression may cause errors. – Raynos Oct 04 '10 at 10:23
  • Oh that's a lovely article. I didn't notice there was actaully a difference between named function expressions and function declaration. – Raynos Oct 04 '10 at 10:30
  • Although actaully I believe my second example above is a function statement. Unles you count assigning the function declaration to arguments[1] as a named function expression. And I was starting to get a feeling that I understood javascript. – Raynos Oct 04 '10 at 10:43
  • 1
    Your second example is definitely a named function expression. It looks identical to a function declaration except for the context: a function declaration isn't valid where an expression is expected (such as when passing a function parameter, as your example does). A function statement is another thing entirely: that's a Mozilla extension to ECMAScript to prevent a function declaration within, say, an `if` block from being a syntax error. kangax's article covers that too: http://kangax.github.com/nfe/#function-statements – Tim Down Oct 04 '10 at 10:49
  • Oh bah I read the article wrong. Yes its a function expression. Out of curiosity does the phrase "named function expression" apply to such statements as var name = function thing() {} ? Or generally when are function expressions considered "named" – Raynos Oct 04 '10 at 11:10
  • Yes, the right hand side of `var name = function thing() {}` is a named function expression. `var name = function() {}` is just a function expression. Distinguishing between named function expressions, function statements and function declarations is all based on context. If it's a place where the interpreter expects an expression (e.g. in a variable declaration) then it'll be a named function expression. If it's in global code or within a function (but not inside a block in either case), it's a function declaration. If it's within a block (e.g. an `if` block), it's a function statement. – Tim Down Oct 04 '10 at 11:38
4

You could do something like this with arrow functions, it works for me on Node.

const createTask = ([name, type = 'default']) => {
  const fn = () => { ... }

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

  return fn
}

MDN is somewhat misleading here:

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

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

This answer provides more details.

Community
  • 1
  • 1
Jack Steam
  • 4,500
  • 1
  • 24
  • 39
1

With ECMAScript2015 (ES2015, ES6) language specification, it is possible to do without the use of slow and unsafe eval function and without Object.defineProperty method which both corrupts function object and does not work in some crucial aspects anyway.

See, for example, this nameAndSelfBind function that is able to both name anonymous functions and renaming named functions, as well as binding their own bodies to themselves as this and storing references to processed functions to be used in an outer scope (JSFiddle):

(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('\nEvent listener 1 triggered:', e, '\nthis: ', this,
                '\n\nremoveEventListener 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('\nEvent listener 2 triggered:', e, '\nthis: ', 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('\nAfter ' + 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);
})();
DDRRSS
  • 306
  • 3
  • 8
0

I normally do: $("object").bind("click" , function name() { alert("x"); });

and don't run into any problems.

Doing so is encouraged in some of the major libraries:

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

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

Andrew Luhring
  • 1,762
  • 1
  • 16
  • 37
-2

If dynamic function name is the issue. You can try this:

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 })();

source: Nate Ferrero

Kobe
  • 6,226
  • 1
  • 14
  • 35
Shai Ben-Yehuda
  • 134
  • 1
  • 2
  • 8
-3

An anonymous function is a function without a name, it is executed from where it is defined. Alternatively, you can define the debugging function before using it.

function debuggingName() { 
    alert("x"); 
}

$("object").bind("click", debuggingName);
Q_Mlilo
  • 1,729
  • 4
  • 23
  • 26