metodos - recorrer array de objetos javascript
Cómo establecer dinámicamente un nombre de función/objeto en Javascript tal como se muestra en Chrome (7)
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 solo necesita llamar al método setName
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}
Esto es algo que me ha estado molestando con el depurador de Google Chrome y me preguntaba si habría alguna forma de solucionarlo.
Estoy trabajando en una gran aplicación de Javascript, usando muchos JS orientados a objetos (usando el framework Joose ), y cuando depuro mi código, todas mis clases reciben un valor de visualización inicial no sensitivo. Para ver lo que quiero decir, prueba 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 puedes expandir para ver todas las propiedades de myObj
, pero lo primero que ves es solo ▶ F
Mi problema es que debido a mi marco OO, cada objeto instanciado recibe el mismo ''nombre'' . El código que se ve 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 siempre es ▶ f
.
Ahora, realmente no quiero cambiar nada acerca de cómo Joose instancia objetos (getMutableCopy ...?) , Pero si hubiera algo que pudiera agregar a esto para poder proporcionar mi propio nombre, sería genial.
Algunas cosas que he visto, pero que no he podido conseguir con:
> function foo {}
> foo.name
"foo"
> foo.name = "bar"
"bar"
> foo.name
"foo" // <-- looks like it is read only
normalmente usas window[name]
como
var name ="bar";
window["foo"+name] = "bam!";
foobar; // "bam!"
que te llevaría a una función como:
function getmc (object, name) {
window[name] = function () {};
window[name].prototype = object;
return new window[name]();
}
pero entonces
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 dado que no puede evaluar una declaración de devolución ( eval("return new name()");
), creo que está atrapado
Esto no resolverá totalmente su problema, pero sugeriría anular 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 verá el nombre de clase original si ingresa una instancia de my_class directamente en la consola (no creo que sea posible hacer algo al respecto), pero obtendrá el buen nombre en los mensajes de error, que encuentro muy útil. Por ejemplo:
a = new my_class()
a.does_not_exist()
Aparecerá el mensaje de error: "TypeError: el nombre del objeto de clase no tiene el método ''does_not_exist''"
He estado jugando con esto durante las últimas 3 horas y finalmente lo he conseguido al menos un poco elegante usando la nueva función 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 el siguiente resultado en su consola:
Book {title: "One Flew to Kill a Mockingbird"}
Aunque es feo, puedes hacer trampa 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 puedes usar nombres que serían válidos como nombres de funciones!
Adición: Para evitar la eval
en cada instanciación de objetos, use un 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));
};
})();
Object.defineProperty(fn, "name", { value: "New Name" });
Hará el truco y es la solución más eficiente. No eval tampoco.
Similar a la respuesta @ Piercey4, pero también tuve que establecer el name
para la instancia:
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''