Используя фабрику конструкторов, я хотел бы, чтобы эти конструкторы имели разные имена в консоли, а также при регистрации их экземпляров.
Вот упрощенный пример моей проблемы:
// 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
Есть ли способ отобразить правильное имя в этом случае?
Протестировано с последней версией Chrome (67). В этом случае я не хочу использовать функцию class
.
Вы бы подумали, что объект с решением для обхода вычисленного свойства может ответить на этот вопрос, но он не работает для сценария конструктора, который вы описываете (по крайней мере, на данный момент в Chrome или Firefox он работает, сейчас, в по крайней мере, Firefox v66; он работает в Edge и, что удивительно для меня, в Node.js, несмотря на то, что Node.js и Chrome оба используют V8 [см. этот комментарий ]):
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.
К сожалению, даже несмотря на то, что Function#name
теперь является определенной функцией функций, как вы обнаружили, это name
не всегда то, что внутренности движков JavaScript используют при трассировке стека и тому подобное (пока, надеюсь, это изменится по мере того, как name
созревает; он был добавлен только в ES2015).
Если вам действительно нужно это сделать, это одно из немногих мест, где вы могли бы достичь для генерации и выполнения динамического кода, такого как new Function
:
var Constructor = new Function("return function " + name + "() { };")();
Это делает следующее, но динамически используя name
вместо nameGoesHere
:
var Constructor = (function() {
return function nameGoesHere() { };
})();
new Function
- это то, что создает внешнюю функцию, которую мы немедленно выполняем.
Живой пример (посмотрите в реальной консоли для вывода):
// 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) ;
Очевидно, это предполагает, что вы не получаете name
из ненадежного источника.
name
не из ненадежного источника.
class Cat { /*...*/ }
. И я не думаю, что вы можете повлиять на вывод консоли без какого-либо очень странного кодаwith(){}
илиeval
.