2011-05-03 22 views
29

Esto es algo que me ha estado molestando con el depurador de Google Chrome y me preguntaba si habría alguna forma de solucionarlo.Cómo establecer dinámicamente un nombre de función/objeto en Javascript tal como se muestra en Chrome

Estoy trabajando en una aplicación de gran Javascript, utilizando una gran cantidad de JS orientados a objetos (utilizando el marco Joose), y cuando puedo depurar mi código, todas mis clases se les da un valor de visualización inicial sin sentido. Para ver lo que quiero decir, probar esto en la consola de Chrome:

var F = function() {}; 
var myObj = new F(); 

console.log(myObj); 

La salida debe ser una sola línea que se puede ampliar para ver todas las propiedades de myObj, pero el primero que se ve es sólo ▶ F.

Mi problema es que debido a mi marco OO, todos los objetos instanciados recibe el mismo 'nombre'. El código que se ve es responsable de esto es así:

getMutableCopy : function (object) { 
    var f = function() {}; 
    f.prototype = object; 
    return new f(); 
} 

Lo que significa que en el depurador, la vista inicial es siempre ▶ f.

Ahora, yo realmente no quiero estar cambiando nada acerca de cómo Joose ejecuta objetos (getMutableCopy ...?), pero si había algo que podía añadir a esto para que pudiera ofrecer mi propia nombre, eso sería genial.

Algunas cosas que he mirado, pero no pudo llegar a ninguna parte con:

> function foo {} 
> foo.name 
    "foo" 
> foo.name = "bar" 
    "bar" 
> foo.name 
    "foo" // <-- looks like it is read only 
+0

Véase también [? Nombre de la función dinámica en javascript] (https://stackoverflow.com/questions/ 5905492/dynamic-function-name-in-javascript/41854075 # 41854075) – gimpf

Respuesta

-1

normalmente se utilizan como window[name]

var name ="bar"; 
window["foo"+name] = "bam!"; 
foobar; // "bam!" 

que daría lugar a una función como:

function getmc (object, name) { 

    window[name] = function() {}; 
    window[name].prototype = object; 
    return new window[name](); 

} 

pero luego

foo = function(){}; 
foobar = getmc(foo, "bar"); 
foobar; // ▶ window 
foobar.name; // foo 
x = new bar; x.name; // foo .. not even nija'ing the parameter works 

y puesto que no se puede eval una declaración de retorno (eval("return new name()");), creo que le pegan

+0

por favor, deje de votar este ... mi respuesta fue correcta antes de cambiar la pregunta –

+1

y luego pls borrar o actualizar su respuesta. –

+0

Upvote para los sentimientos ;-) – lama12345

5

pesar de que es feo, usted podría engañar a través de eval():

function copy(parent, name){ 
    name = typeof name==='undefined'?'Foobar':name; 
    var f = eval('function '+name+'(){};'+name); 
    f.prototype = parent; 
    return new f(); 
} 

var parent = {a:50}; 
var child = copy(parent, 'MyName'); 
console.log(child); // Shows 'MyName' in Chrome console. 

Cuidado : ¡Solo puede usar nombres que serían válidos como nombres de funciones!

Adición: Para evitar eval ING en cada instanciación de objetos, utilizar una memoria caché:

function Cache(fallback){ 
    var cache = {}; 

    this.get = function(id){ 
    if (!cache.hasOwnProperty(id)){ 
     cache[id] = fallback.apply(null, Array.prototype.slice.call(arguments, 1)); 
    } 
    return cache[id]; 
    } 
} 

var copy = (function(){ 
    var cache = new Cache(createPrototypedFunction); 

    function createPrototypedFunction(parent, name){ 
    var f = eval('function '+name+'(){};'+name); 
    f.prototype = parent; 
    return f; 
    } 

    return function(parent, name){ 
    return new (cache.get(name, parent, typeof name==='undefined'?'Foobar':name)); 
    }; 
})(); 
+0

+1 - buena idea. Desafortunadamente, tengo demasiado miedo del costo de rendimiento de realizar una evaluación en cada creación de instancia de un solo objeto. – nickf

+0

Se agregó una versión con un caché. – GodsBoss

+0

Funciona para la matriz pasada. Pero necesito pasar la función de constructor a la función nombrada. –

2

Esto no va a resolver totalmente el problema, pero sugeriría reemplazando el método toString en el prototipo de la clase. Por ejemplo:

my_class = function() {} 
my_class.prototype.toString = function() { return 'Name of Class'; } 

Todavía se verá el nombre de la clase original, si se introduce una instancia de my_class directamente en la consola (no creo que sea posible hacer nada acerca de esto), sino que obtendrá el bonito nombre en los mensajes de error, que me parece muy útil.Por ejemplo:

a = new my_class() 
a.does_not_exist() 

daré el mensaje de error: "TypeError: Objeto Nombre de la clase no tiene un método 'does_not_exist'"

14

He estado jugando con esto durante los últimos 3 horas y finalmente consiguió que al menos algo elegante utilizando las nuevas funciones como se sugiere en otros hilos:

/** 
* JavaScript Rename Function 
* @author Nate Ferrero 
* @license Public Domain 
* @date Apr 5th, 2014 
*/ 
var renameFunction = function (name, fn) { 
    return (new Function("return function (call) { return function " + name + 
     "() { return call(this, arguments) }; };")())(Function.apply.bind(fn)); 
}; 

/** 
* Test Code 
*/ 
var cls = renameFunction('Book', function (title) { 
    this.title = title; 
}); 

new cls('One Flew to Kill a Mockingbird'); 

Si ejecuta el código anterior, debería ver la siguiente salida a la consola:

Book {title: "One Flew to Kill a Mockingbird"} 
+1

Parece que [¿Hay alguna forma no-eval para crear una función con un nombre determinado en tiempo de ejecución?] (Http://stackoverflow.com/q/9479046/1048572) :-) – Bergi

+0

¿Está disponible para la clase (es6)? que es un tipo de Función? –

0

Creo que esta es la mejor manera de establecer dinámicamente el nombre de una función:

Function.prototype.setName = function (newName) { 
     Object.defineProperty(this,'name', { 
      get : function() { 
       return newName; 
      } 
     }); 
    } 

Ahora sólo tiene que llamar al setName método

function foo() { } 
foo.name; // returns 'foo' 

foo.setName('bar'); 
foo.name; // returns 'bar' 

foo.name = 'something else'; 
foo.name; // returns 'bar' 

foo.setName({bar : 123}); 
foo.name; // returns {bar : 123} 
+1

Google Chrome arroja un error en la consola "TypeError: No se puede redefinir la propiedad: nombre" –

37
Object.defineProperty(fn, "name", { value: "New Name" }); 

hará el truco y es la solución más eficiente. No eval tampoco.

+0

Con mucho, la mejor respuesta. Utiliza la API que pretende definir propiedades como el nombre que, de lo contrario, es de solo lectura. – Michael

+2

Esto no parece funcionar para mí: '' 'función caat() {this.legs = 4; } Object.defineProperty (CAAT, "nombre", {valor: "gato"}) milo = new CAAT() { CAAT piernas: 4} '' ' estoy esperando para controlar la salida de la nombre en esa última línea, pero no parece usar la propiedad del nombre al imprimir en la consola. – speg

+0

Parece que desea editar el prototipo 'caat' como' Object.defineProperty (caat.prototype, "name", {value: "cat"}) '. – Piercey4

0

similares a @ Piercey4 respuesta, pero tuve que ajustar el name para la instancia, así:

function generateConstructor(newName) { 
    function F() { 
    // This is important: 
    this.name = newName; 
    }; 

    Object.defineProperty(F, 'name', { 
    value: newName, 
    writable: false 
    }); 

    return F; 
} 

const MyFunc = generateConstructor('MyFunc'); 
const instance = new MyFunc(); 

console.log(MyFunc.name); // prints 'MyFunc' 
console.log(instance.name); // prints 'MyFunc' 
Cuestiones relacionadas