Function Names

There are cases where your code may want to introspect on itself and ask what the name of some function is. If you ask what a function’s name is, the answer is surprisingly somewhat ambiguous. Consider:

  1. function daz() {
  2. // ..
  3. }
  4. var obj = {
  5. foo: function() {
  6. // ..
  7. },
  8. bar: function baz() {
  9. // ..
  10. },
  11. bam: daz,
  12. zim() {
  13. // ..
  14. }
  15. };

In this previous snippet, “what is the name of obj.foo()“ is slightly nuanced. Is it "foo", "", or undefined? And what about obj.bar() — is it named "bar" or "baz"? Is obj.bam() named "bam" or "daz"? What about obj.zim()?

Moreover, what about functions which are passed as callbacks, like:

  1. function foo(cb) {
  2. // what is the name of `cb()` here?
  3. }
  4. foo( function(){
  5. // I'm anonymous!
  6. } );

There are quite a few ways that functions can be expressed in programs, and it’s not always clear and unambiguous what the “name” of that function should be.

More importantly, we need to distinguish whether the “name” of a function refers to its name property — yes, functions have a property called name — or whether it refers to the lexical binding name, such as bar in function bar() { .. }.

The lexical binding name is what you use for things like recursion:

  1. function foo(i) {
  2. if (i < 10) return foo( i * 2 );
  3. return i;
  4. }

The name property is what you’d use for meta programming purposes, so that’s what we’ll focus on in this discussion.

The confusion comes because by default, the lexical name a function has (if any) is also set as its name property. Actually there was no official requirement for that behavior by the ES5 (and prior) specifications. The setting of the name property was nonstandard but still fairly reliable. As of ES6, it has been standardized.

Tip: If a function has a name value assigned, that’s typically the name used in stack traces in developer tools.

Inferences

But what happens to the name property if a function has no lexical name?

As of ES6, there are now inference rules which can determine a sensible name property value to assign a function even if that function doesn’t have a lexical name to use.

Consider:

  1. var abc = function() {
  2. // ..
  3. };
  4. abc.name; // "abc"

Had we given the function a lexical name like abc = function def() { .. }, the name property would of course be "def". But in the absence of the lexical name, intuitively the "abc" name seems appropriate.

Here are other forms that will infer a name (or not) in ES6:

  1. (function(){ .. }); // name:
  2. (function*(){ .. }); // name:
  3. window.foo = function(){ .. }; // name:
  4. class Awesome {
  5. constructor() { .. } // name: Awesome
  6. funny() { .. } // name: funny
  7. }
  8. var c = class Awesome { .. }; // name: Awesome
  9. var o = {
  10. foo() { .. }, // name: foo
  11. *bar() { .. }, // name: bar
  12. baz: () => { .. }, // name: baz
  13. bam: function(){ .. }, // name: bam
  14. get qux() { .. }, // name: get qux
  15. set fuz() { .. }, // name: set fuz
  16. ["b" + "iz"]:
  17. function(){ .. }, // name: biz
  18. [Symbol( "buz" )]:
  19. function(){ .. } // name: [buz]
  20. };
  21. var x = o.foo.bind( o ); // name: bound foo
  22. (function(){ .. }).bind( o ); // name: bound
  23. export default function() { .. } // name: default
  24. var y = new Function(); // name: anonymous
  25. var GeneratorFunction =
  26. function*(){}.__proto__.constructor;
  27. var z = new GeneratorFunction(); // name: anonymous

The name property is not writable by default, but it is configurable, meaning you can use Object.defineProperty(..) to manually change it if so desired.