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 ''

Share Improve this question asked Jul 15, 2016 at 15:34 EnbyCherryEnbyCherry 1,3121 gold badge17 silver badges40 bronze badges 9
  • 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
 |  Show 4 more ments

1 Answer 1

Reset to default 9

As 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