admin管理员组文章数量:1417093
As we all know, we can define functions with and without a name:
var/let/const foo = function() {}
function bar() {}
Where foo
's function hasn't got it's own name, but bar
does.
console.log(foo.name) --> ''
console.log(bar.name) --> 'bar'
Is it possible to define the name of a function after defining it?
So doing something makes console.log(foo.name)
return something else than ''
As we all know, we can define functions with and without a name:
var/let/const foo = function() {}
function bar() {}
Where foo
's function hasn't got it's own name, but bar
does.
console.log(foo.name) --> ''
console.log(bar.name) --> 'bar'
Is it possible to define the name of a function after defining it?
So doing something makes console.log(foo.name)
return something else than ''
-
Have you tried
foo.name = 'foo';
? – jonhopkins Commented Jul 15, 2016 at 15:36 -
6
Object.defineProperty(foo, "name", {value: "foo"})
– user1106925 Commented Jul 15, 2016 at 15:36 - 1 @jonhopkins Have you tried it? :-3 – deceze ♦ Commented Jul 15, 2016 at 15:36
-
2
@squint is right.
name
is only configurable, not writeable. – nils Commented Jul 15, 2016 at 15:37 - 1 squint and nils are right: ecma-international/ecma-262/7.0/… Note how they explicitly make it configurable. – T.J. Crowder Commented Jul 15, 2016 at 15:46
1 Answer
Reset to default 9As we all know...
var/let/const foo = function() {}
...
foo's function hasn't got its own name...
As of ES2015+, foo's function does indeed have a name: foo
. ES2015 added a lot of places where functions get names even when defined with "anonymous" function expressions. This includes simple assignments like that, assignments to properties (including puted property names), and other such. Search the spec for "SetFunctionName" for details.
But as squint points out in a ment, in ES2015+, a function's name can be set via Object.defineProperty
:
Object.defineProperty(foo, "name", {value: "aNameForFoo"});
You can't just assign to foo.name
because name
is defined as non-writable. But it's configurable (you can swap out the property with a new one), so the above works. (Details on how it's defined in the spec.)
Note that Function#name
is new as of ES2015, and as it was a quite minor feature, it was one of the lowest priorities for JavaScript engine developers. I believe Chrome 51 was the first browser with a JavaScript engine that correctly implements the spec. That'll change quickly at this stage.
But as Assimilater points out, if you just want the function created by the expression to have a name and you don't need it defined at runtime, just use a named function expression (NFE):
var foo = function bar() {
// Note ------^^^^
}
//console.log(bar); // Would throw a ReferenceError, `bar` is not defined in this scope
console.log(foo.name); // "bar"
NFEs have been around forever, long before ES2015. They used to be problematic in some engines (very early Safari, IE8 and earlier), but modern engines (IE9+) handle them correctly.
Here's an example of:
- The "inferred" name
- The updated name
- A name assigned by an NFE
// "Inferred" name is foo
var foo = function() {
throw new Error();
};
try {
foo();
} catch (e) {
console.log(e.stack);
}
// Change it to "updatedName"
Object.defineProperty(foo, "name", {
value: "updatedName"
});
try {
foo();
} catch (e) {
console.log(e.stack);
}
// Example of NFE
var foo2 = function bar() {
// Note --------^^^^
console.log("bar is defined within the function: " + bar.name);
throw new Error();
};
//console.log(bar); // Would throw an error, `bar is not
// defined here
console.log(foo2.name); // "bar"
try {
foo2();
} catch (e) {
console.log(e.stack);
}
On a browser that implements ES2015's Function#name
correctly (very few do as of this writing, Chrome 51 being one of the first) and which implements Error#stack
, that outputs:
Error at foo (http://stacksnippets/js:15:9) at http://stacksnippets/js:18:3 Error at updatedName (http://stacksnippets/js:15:9) at http://stacksnippets/js:28:3 bar bar is defined within the function: bar Error at bar (http://stacksnippets/js:37:9) at http://stacksnippets/js:43:3
A note about "inferred" names for functions defined by anonymous expressions. Consider:
let Nifty = {
stuff: {
here: {
foo: function() { throw new Error(); }
}
}
};
let f = Nifty.stuff.here.foo;
console.log(f.name); // "foo"
One could reasonably think the function would end up being Nifty.stuff.here.foo
, or foo
. It's the latter. (This ES2015 name "inference" came out of efforts at Google and Mozilla to provide useful names for functions in their dev tools. At one stage, one or the other — I forget which — was using the full name, but it appears not to have been popular.)
Perhaps worth noting: You can choose a runtime name when creating it, as of ES2015, via a puted property name:
var name = "function" + Math.floor(Math.random() * 10000);
var obj = {[name]: function() { throw new Error(); }};
var foo = obj[name];
try {
foo();
} catch (e) {
console.log(e.stack);
}
Output on a browser supporting this stuff:
Error at function3608 (http://stacksnippets/js:14:39) at http://stacksnippets/js:17:3
But now that I know you can do the Object.defineProperty
trick, well, that seems less clever. :-)
本文标签: javascriptSet function name after defining itStack Overflow
版权声明:本文标题:javascript - Set function name after defining it - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745253772a2649978.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论