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:
function daz() {
// ..
}
var obj = {
foo: function() {
// ..
},
bar: function baz() {
// ..
},
bam: daz,
zim() {
// ..
}
};
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:
function foo(cb) {
// what is the name of `cb()` here?
}
foo( function(){
// I'm anonymous!
} );
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:
function foo(i) {
if (i < 10) return foo( i * 2 );
return i;
}
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:
var abc = function() {
// ..
};
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:
(function(){ .. }); // name:
(function*(){ .. }); // name:
window.foo = function(){ .. }; // name:
class Awesome {
constructor() { .. } // name: Awesome
funny() { .. } // name: funny
}
var c = class Awesome { .. }; // name: Awesome
var o = {
foo() { .. }, // name: foo
*bar() { .. }, // name: bar
baz: () => { .. }, // name: baz
bam: function(){ .. }, // name: bam
get qux() { .. }, // name: get qux
set fuz() { .. }, // name: set fuz
["b" + "iz"]:
function(){ .. }, // name: biz
[Symbol( "buz" )]:
function(){ .. } // name: [buz]
};
var x = o.foo.bind( o ); // name: bound foo
(function(){ .. }).bind( o ); // name: bound
export default function() { .. } // name: default
var y = new Function(); // name: anonymous
var GeneratorFunction =
function*(){}.__proto__.constructor;
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.