Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript change constructor name in console

Using a factory of constructors, I would like those constructors to have different names in the console, also when logging instances of them.

Here is a simplified example of my problem :

// Constructor factory //
function type(name, prototype) {
    function Constructor() {}
    Constructor.name ; // "Constructor"
    // Constructor.name = name  won't work properly.
    Object.defineProperty(Constructor, 'name', { value:name }) ;
    Constructor.prototype = prototype ;

    window[name] = Constructor ;
    return Constructor ;
}

// Creating constructor and instance //
type('Cat', { name:"", paws:4 }) ;
var chat = new Cat ;

// Tests //
Cat.name ; // "Cat"    -> Correct name
Cat ; // Constructor() { ... }     -> Incorrect name
chat ; // Constructor {name:"", paws:4}     -> Incorrect name

Is there any way to display the right name in this case ?

Tested with the latest version of Chrome (67). In this case I don't want to use class feature.

like image 585
Tot Avatar asked Mar 21 '26 21:03

Tot


1 Answers

You'd be tempted to think the object with computed property workaround answer to this question would work, but it doesn't work for the constructor scenario you describe (at least, at the moment, in Chrome or Firefox it does, now, in at least Firefox v66; it does in Edge and, surprisingly to me, in Node.js despite the fact Node.js and Chrome both use V8 [see this comment]):

const dynamicName = "foo" + Math.floor(Math.random() * 1000);
const obj = {
  [dynamicName]: function() {
  }
};
const f = obj[dynamicName];
const inst = new f();
console.log(f.name);	// works
console.log(f);				// nope (on Chrome)
console.log(inst);		// nope (on Chrome)
Look in the real console.

Unfortunately, even though Function#name is now a specified feature of functions, as you've found, that name isn't always what the internals of the JavaScript engines use in stack traces and such (yet; hopefully this changes as name matures; it was only added in ES2015).

If you really need to do this, it's one of the very few places where you'd reach for generating and executing dynamic code, such as new Function:

var Constructor = new Function("return function " + name + "() { };")();

That does the following, but dynamically using name instead of nameGoesHere:

var Constructor = (function() {
    return function nameGoesHere() { };
})();

The new Function is what creates the outer function we immediately execute.

Live Example (look in the real console for output):

// Constructor factory //
function type(name, prototype) {
    var Constructor = new Function("return function " + name + "() { };")();

    window[name] = Constructor ;
    return Constructor ;
}

// Creating constructor and instance //
type('Cat', { name:"", paws:4 }) ;
var chat = new Cat ;

// Tests //
console.log(Cat.name) ;
console.log(Cat) ;
console.log(chat) ;

Obviously, this assumes you aren't getting name from an untrusted source.

like image 70
T.J. Crowder Avatar answered Mar 23 '26 10:03

T.J. Crowder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!