3

Is it possible to set the name of a function at runtime in JavaScript?

var ctor = function() {}; // Anonymous function because I don't know the name ahead of runtime.
ctor.name = 'foo'; // Pseudocode  - this is effectively what I want to do

I want the above to be equivalent to:

var ctor = function foo() {};

Edit

Here is an example use-case:

function mix(fn1, fn2, name) {    
    var ctor = function() {};
    ctor.name = name; // Vain attempt to set the name of the function.
    ctor.prototype = Object.create(fn1.prototype);

    Object.keys(fn2.prototype).map(function(k) {
        ctor.prototype[k] = fn2.prototype[k];
    });

    // Return a constructor function with the prototype configured.
    return ctor;
}

function Foo() {}
Foo.prototype.foo = function(){};

function Bar(){}
Bar.prototype.bar = function() {};

var Foobar = mix(Foo, Bar, 'Foobar');
console.log(new Foobar()); // ctor {bar: function, foo: function} (in Chrome) - I wanted Foobar { bar: function, foo: function }
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • Have you tried using `eval`? – Andrew Koroluk Mar 04 '15 at 18:24
  • 1
    Check out http://stackoverflow.com/questions/5871040/how-to-dynamically-set-a-function-object-name-in-javascript-as-it-is-displayed-i – flyandi Mar 04 '15 at 18:25
  • Why do you want to do this? (Not hypothetical -- this could influence the nature of the answer.) – apsillers Mar 04 '15 at 18:26
  • @apsillers I was considering the case whereby a constructor function is created at runtime, and I wanted the resulting function to have sensible metadata behind the scenes so that debuging, logging etc is more meaningful. – Ben Aston Mar 04 '15 at 18:42

2 Answers2

3

name was a non-standard only supported by some browsers.

Now, it has been standardized in ECMAScript 6:

19.2.4.2 name

The value of the name property is an String that is descriptive of the function. The name has no semantic significance but is typically a variable or property name that is used to refer to the function at its point of definition in ECMAScript code. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

Anonymous functions objects that do not have a contextual name associated with them by this specification do not have a name own property but inherit the name property of %FunctionPrototype%.

Therefore, your code will work on browsers that don't support name, but the new property will be writable and enumerable. And on browsers that support it, your code won't work because name is not writable.

Therefore, a better equivalent code would be

Object.defineProperty(ctor, 'name', {
    value: 'foo',
    configurable: true
});
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

Disclaimer: This may be upsetting for some people who like their code to be safe and predictable.

Of course, you won't actually do this, because you're sensible, right?

function rename(fn, name) {
  var fnStr = fn.toString().replace(/function/, 'function ' + name);
  eval.call(window, fnStr);
  return window[name];
}

var tmp = function(a, b) { return a + b; };
rename(tmp, 'add');
add(3, 4); // 7

Of course, depending on how well behaved you need to be (not very if you use eval), you could (but you won't) go one step further.

Function.prototype.rename = function(name) {
  return rename(this, name);
};

Do this in actual code and people will hate you, but that's ok, because you won't.

There are a few hiccups (and probably some broken edge cases) to do with the scope in which the function was defined. Eval uses the context of this to decide which scope to operate within, so passing the window object means the renamed function will always be defined within the window object.

Fairly contrived example, but it should give you some idea of the pitfalls.

function init() {
  function go() {
    return 'go';
  };

  var ctor = function() {
    return 'ctor';
  };

  rename(ctor, 'go');
  go(); // 'go'

  next();  
}

function next() {
  go(); // 'ctor'
}
Dan Prince
  • 29,491
  • 13
  • 89
  • 120