Update 2015-12-26: Sections for two caveats: “the name of a function is always assigned at creation” and “minification”
The name
property of a function contains its name:
> function foo() {}
> foo.name
'foo'
This property is useful for debugging (its value shows up in stack traces) and some metaprogramming tasks (picking a function by name etc.).
Prior to ECMAScript 6 (ES6), this property was already supported by most engines. With ES6, it becomes part of the language standard and is frequently filled in automatically.
The following sections describe how name
is set up automatically for various programming constructs.
Functions pick up names if they are created via variable declarations:
let func1 = function () {};
console.log(func1.name); // func1
const func2 = function () {};
console.log(func2.name); // func2
var func3 = function () {};
console.log(func3.name); // func3
But even with a normal assignment, name
is set up properly:
let func4;
func4 = function () {};
console.log(func4.name); // func4
var func5;
func5 = function () {};
console.log(func5.name); // func5
With regard to names, arrow functions are like anonymous function expressions:
const func = () => {};
console.log(func.name); // func
From now on, whenever you see an anonymous function expression, you can assume that an arrow function works the same way.
If a function is a default value, it gets its name from its variable or parameter:
let [func1 = function () {}] = [];
console.log(func1.name); // func1
let { f2: func2 = function () {} } = {};
console.log(func2.name); // func2
function g(func3 = function () {}) {
return func3.name;
}
console.log(g()); // func3
Function declarations and function expression are function definitions. This scenario has been supported for a long time: a function definition with a name passes it on to the name
property.
For example, a function declaration:
function foo() {}
console.log(foo.name); // foo
The name of a named function expression also sets up the name
property.
const bar = function baz() {};
console.log(bar.name); // baz
Because it comes first, the function expression’s name baz
takes precedence over other names (e.g. the name bar
provided via the variable declaration):
However, as in ES5, the name of a function expression is only a variable inside the function expression:
const bar = function baz() {
console.log(baz.name); // baz
};
bar();
console.log(baz); // ReferenceError
If a function is the value of a property, it gets its name from that property. It doesn’t matter if that happens via a method definition (line A), a traditional property definition (line B), a property definition with a computed property key (line C) or a property value shorthand (line D).
function func() {}
let obj = {
m1() {}, // (A)
m2: function () {}, // (B)
['m' + '3']: function () {}, // (C)
func, // (D)
};
console.log(obj.m1.name); // m1
console.log(obj.m2.name); // m2
console.log(obj.m3.name); // m3
console.log(obj.func.name); // func
The names of getters are prefixed with 'get'
, the names of setters are prefixed with 'set'
:
let obj = {
get foo() {},
set bar(value) {},
};
let getter = Object.getOwnPropertyDescriptor(obj, 'foo').get;
console.log(getter.name); // 'get foo'
let setter = Object.getOwnPropertyDescriptor(obj, 'bar').set;
console.log(setter.name); // 'set bar'
The naming of methods in class definitions is similar to object literals:
class C {
m1() {}
['m' + '2']() {} // computed property key
static classMethod() {}
}
console.log(C.prototype.m1.name); // m1
console.log(new C().m1.name); // m1
console.log(C.prototype.m2.name); // m2
console.log(C.classMethod.name); // classMethod
Getters and setters again have the name prefixes 'get'
and 'set'
, respectively:
class C {
get foo() {}
set bar(value) {}
}
let getter = Object.getOwnPropertyDescriptor(C.prototype, 'foo').get;
console.log(getter.name); // 'get foo'
let setter = Object.getOwnPropertyDescriptor(C.prototype, 'bar').set;
console.log(setter.name); // 'set bar'
In ES6, the key of a method can be a symbol. The name
property of such a method is still a string:
''
).const key1 = Symbol('description');
const key2 = Symbol();
let obj = {
[key1]() {},
[key2]() {},
};
console.log(obj[key1].name); // '[description]'
console.log(obj[key2].name); // ''
Remember that class definitions create functions. Those functions also have their property name
set up correctly:
class Foo {}
console.log(Foo.name); // Foo
const Bar = class {};
console.log(Bar.name); // Bar
All of the following statements set name
to 'default'
:
export default function () {}
export default (function () {});
export default class {}
export default (class {});
export default () => {};
Generator functions and generator methods get their names the same way that normal functions and methods do.
new Function()
produces functions whose name
is 'anonymous'
. A webkit bug describes why that is necessary on the web.
func.bind(···)
produces a function whose name
is 'bound '+func.name
:
function foo(x) {
return x
}
const bound = foo.bind(undefined, 123);
console.log(bound.name); // 'bound foo'
Function names are always assigned during creation and never changed later on. That is, JavaScript engines detect the previously mentioned patterns and create functions that start their lives with the correct names. The following code demonstrates that the name of the function created by functionFactory()
is assigned in line A and not changed by the declaration in line B.
function functionFactory() {
return function () {}; // (A)
}
const foo = functionFactory(); // (B)
console.log(foo.name.length); // 0 (anonymous)
One could, in theory, check for each assignment whether the right-hand side evaluates to a function and whether that function doesn’t have a name, yet. But that would incur a significant performance penalty.
Function names are subject to minification, which means that they will usually change in minified code. Depending on what you want to do, you may have to manage function names via strings (which are not minified) or you may have to tell your minifier what names not to minify.
These are the attributes of property name
:
> let func = function () {}
> Object.getOwnPropertyDescriptor(func, 'name')
{ value: 'func',
writable: false,
enumerable: false,
configurable: true }
The property not being writable means that you can’t change its value via assignment:
> func.name = 'foo';
> func.name
'func'
The property is, however, configurable, which means that you can change it by re-defining it:
> Object.defineProperty(func, 'name', {value: 'foo', configurable: true});
> func.name
'foo'
If the property name
already exists then you can omit the descriptor property configurable
, because missing descriptor properties mean that the corresponding attributes are not changed.
If the property name
does not exist yet then the descriptor property configurable
ensures that name
remains configurable (the default attribute values are all false
or undefined
).
name
in the spec SetFunctionName()
sets up the property name
. Search for its name in the spec to find out where that happens.
'get'
and 'set'
)Function.prototype.bind()
(prefix 'bound'
)name
can be seen by looking at their runtime semantics:
SetFunctionName()
. That operation is not invoked for anonymous function expressions.SetFunctionName()
is not invoked).name
property in engines In Kangax’ ES6 table, you can see that no engine currently fully supports name
, not even Babel. Thus, the code in this blog post shows how things should be, not how they are in any single engine.
Further reading: “Callable entities in ECMAScript 6” in “Exploring ES6”.