tablas - obtener datos de una tabla html javascript
Nombre de la función dinámica en javascript? (18)
Tengo esto:
this.f = function instance(){};
Me gustaría tener esto:
this.f = function ["instance:" + a](){};
actualizar
Como otros mencionaron, esta no es la solución más rápida ni la más recomendada. La solución de Marcosc a continuación es el camino a seguir.
Puedes usar eval:
var code = "this.f = function " + instance + "() {...}";
eval(code);
¡Gracias, Marcosc! Basándose en su respuesta, si quiere renombrar cualquier función, use esto:
// returns the function named with the passed name
function namedFunction(name, fn) {
return new Function(''fn'',
"return function " + name + "(){ return fn.apply(this,arguments)}"
)(fn)
}
Creo que la mayoría de las sugerencias aquí son subóptimas, mediante el uso de soluciones eval, hacky o wrappers. A partir de ES2015, los nombres se deducen de la posición sintáctica de las variables y propiedades.
Entonces esto funcionará bien:
const name = ''myFn'';
const fn = {[name]: function() {}}[name];
fn.name // ''myFn''
Resista la tentación de crear métodos de fábrica de funciones nombradas ya que no podría pasar la función desde el exterior y adaptarla a la posición sintáctica para inferir su nombre. Entonces ya es demasiado tarde. Si realmente lo necesita, debe crear un contenedor. Alguien hizo eso aquí, pero esa solución no funciona para las clases (que también son funciones).
Se ha escrito una respuesta mucho más detallada con todas las variantes descritas aquí: https://.com/a/9479081/633921
En motores recientes, puedes hacer
function nameFunction(name, body) {
return {[name](...args) {return body(...args)}}[name]
}
const x = nameFunction("wonderful function", (p) => p*2)
console.log(x(9)) // => 18
console.log(x.name) // => "wonderful function"
Esta función de utilidad combina múltiples funciones en una sola (usando un nombre personalizado), el único requisito es que las funciones proporcionadas estén correctamente "alineadas" al inicio y al final de su primicia.
const createFn = function(name, functions, strict=false) {
var cr = `/n`, a = [ ''return function '' + name + ''(p) {'' ];
for(var i=0, j=functions.length; i<j; i++) {
var str = functions[i].toString();
var s = str.indexOf(cr) + 1;
a.push(str.substr(s, str.lastIndexOf(cr) - s));
}
if(strict == true) {
a.unshift(''/"use strict/";'' + cr)
}
return new Function(a.join(cr) + cr + ''}'')();
}
// test
var a = function(p) {
console.log("this is from a");
}
var b = function(p) {
console.log("this is from b");
}
var c = function(p) {
console.log("p == " + p);
}
var abc = createFn(''aGreatName'', [a,b,c])
console.log(abc) // output: function aGreatName()
abc(123)
// output
this is from a
this is from b
p == 123
Estabas cerca:
this["instance_" + a] = function () {...};
{...};
Esto básicamente lo hará en el nivel más simple:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert(''sweet!'')}"
)();
//call it, to test it
func();
Si quieres ser más elegante, tengo un artículo escrito sobre " Nombres de funciones dinámicas en JavaScript ".
Hay dos métodos para lograr esto, y tienen sus pros y sus contras.
name
propiedad definición
Definición de la propiedad del name
inmutable de una función.
Pros
- Cada personaje está disponible para el nombre. (ej..
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)
Contras
- El nombre sintáctico ("expresivo") de la función puede no corresponderse con el valor de propiedad de su
name
.
Evaluación de expresión de función
Hacer una expresión de función nombrada y evaluarla con el constructor de Function
.
Pros
- El nombre sintáctico ("expresivo") de la función siempre se corresponde con el valor de propiedad de su
name
.
Contras
- Los espacios en blanco (y etc.) no están disponibles para el nombre.
- Expresión inyectable (por ejemplo, para input
(){}/1//
, la expresión esreturn function (){}/1//() {}
, daNaN
lugar de una función.).
const demoeval = expr => (new Function(`return ${expr}`))();
// `name` property definition
const method1 = func_name => {
const anon_func = function() {};
Object.defineProperty(anon_func, "name", {value: func_name, writable: false});
return anon_func;
};
const test11 = method1("DEF_PROP"); // No whitespace
console.log("DEF_PROP?", test11.name); // "DEF_PROP"
console.log("DEF_PROP?", demoeval(test11.toString()).name); // ""
const test12 = method1("DEF PROP"); // Whitespace
console.log("DEF PROP?", test12.name); // "DEF PROP"
console.log("DEF PROP?", demoeval(test12.toString()).name); // ""
// Function expression evaluation
const method2 = func_name => demoeval(`function ${func_name}() {}`);
const test21 = method2("EVAL_EXPR"); // No whitespace
console.log("EVAL_EXPR?", test21.name); // "EVAL_EXPR"
console.log("EVAL_EXPR?", demoeval(test21.toString()).name); // "EVAL_EXPR"
const test22 = method2("EVAL EXPR"); // Uncaught SyntaxError: Unexpected identifier
La function[i](){}
sintaxis function[i](){}
implica un objeto con valores de propiedad que son funciones, function[]
, indexado por el nombre, [i]
.
Así
{"f:1":function(){}, "f:2":function(){}, "f:A":function(){}, ... } ["f:"+i]
.
{"f:1":function f1(){}, "f:2":function f2(){}, "f:A":function fA(){}} ["f:"+i]
preservará identificación del nombre de la función. Ver notas a continuación con respecto a :
Asi que,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
muestra ({f:(function () {})})
en FireFox.
(Esta es casi la misma idea que esta solución , solo que utiliza un objeto genérico y ya no rellena directamente el objeto de la ventana con las funciones).
Este método rellena explícitamente el entorno con la instance:x
.
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
muestra
({f:(function () {})})
y
function () {
}
Aunque la función de propiedad f
referencia a una anonymous function
y no instance:x
, este método evita varios problemas con esta solución .
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
muestra solo
({f:(function instanceA() {})})
- El incrustado
:
hace que lafunction instance:a(){}
javascriptfunction instance:a(){}
inválida. - En lugar de una referencia, la definición de texto real de la función es analizada e interpretada por
eval
.
Lo siguiente no es necesariamente problemático,
- La función
instanceA
no está disponible directamente para su uso comoinstanceA()
y entonces es mucho más consistente con el contexto del problema original.
Teniendo en cuenta estas consideraciones,
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
mantiene el entorno informático global con la semántica y la sintaxis del ejemplo OP todo lo posible.
La respuesta más votada ya tiene definido el cuerpo de la función [String]. Estaba buscando la solución para renombrar el nombre de la función ya declarada y, finalmente, después de una hora de lucha, lo he solucionado. Eso:
- toma la función declarada alredy
- lo analiza en [String] con el método
.toString()
- luego sobrescribe el nombre (de la función nombrada) o agrega el nuevo (cuando es anónimo) entre la
function
y(
- luego crea la nueva función renombrada con el
new Function()
constructornew Function()
function nameAppender(name,fun){
const reg = /^(function)(?:/s*|/s+([A-Za-z0-9_$]+)/s*)(/()/;
return (new Function(`return ${fun.toString().replace(reg,`$1 ${name}$3`)}`))();
}
//WORK FOR ALREADY NAMED FUNCTIONS:
function hello(name){
console.log(''hello '' + name);
}
//rename the ''hello'' function
var greeting = nameAppender(''Greeting'', hello);
console.log(greeting); //function Greeting(name){...}
//WORK FOR ANONYMOUS FUNCTIONS:
//give the name for the anonymous function
var count = nameAppender(''Count'',function(x,y){
this.x = x;
this.y = y;
this.area = x*y;
});
console.log(count); //function Count(x,y){...}
Los métodos dinámicos de un objeto se pueden crear utilizando Object Literal Extensions provistos por ECMAScript 2015 (ES6):
const postfixes = [''foo'', ''bar''];
const mainObj = {};
const makeDynamic = (postfix) => {
const newMethodName = ''instance: '' + postfix;
const tempObj = {
[newMethodName]() {
console.log(`called method ${newMethodName}`);
}
}
Object.assign(mainObj, tempObj);
return mainObj[newMethodName]();
}
const processPostfixes = (postfixes) => {
for (const postfix of postfixes) {
makeDynamic(postfix);
}
};
processPostfixes(postfixes);
console.log(mainObj);
El resultado de ejecutar el código anterior es:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
Me puede estar perdiendo lo obvio aquí, pero ¿qué hay de malo con solo agregar el nombre? las funciones se invocan independientemente de su nombre. los nombres solo se usan por razones de alcance. si lo asigna a una variable, y está dentro del alcance, se puede invocar. sucede cuando estás ejecutando una variable que resulta ser una función. si debe tener un nombre para los motivos de identificación cuando se depura, insértelo entre la función de palabra clave y la llave de apertura.
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
un enfoque alternativo es envolver la función en una corrección externa renombrada, que también puede pasar a una envoltura externa, si no desea ensuciar el espacio de nombres circundante. si quiere crear dinámicamente la función a partir de cadenas (lo que ocurre en la mayoría de estos ejemplos), es trivial cambiar el nombre del origen para hacer lo que quiera. sin embargo, si desea cambiar el nombre de las funciones existentes sin afectar su funcionalidad cuando se le llama a otra parte, un ajuste es la única forma de lograrlo.
(function(renamedFunction) {
alert(renamedFunction(1,2));
alert(renamedFunction.name);
alert(renamedFunction.toString());
alert(renamedFunction.apply(this,[1,2]));
})(function renamedFunction(){return namedFunction.apply(this,arguments);});
function namedFunction(a,b){return a+b};
Para configurar el nombre de una función anónima existente :
(Basado en la respuesta de @Marcosc)
var anonymous = function() { return true; }
var name = ''someName'';
var strFn = anonymous.toString().replace(''function '', ''return function '' + name);
var fn = new Function(strFn)();
console.log(fn()); // —> true
Puede usar Object.defineProperty como se indica en la Referencia de JavaScript de MDN [1]:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, ''name'', {value: myName, writable: false});
Qué pasa
this.f = window["instance:" + a] = function(){};
El único inconveniente es que la función en su método toSource no indicaría un nombre. Eso suele ser solo un problema para los depuradores.
Tuve mejor suerte al combinar la respuesta de Darren y la respuesta de kyernetikos .
const nameFunction = function (fn, name) {
return Object.defineProperty(fn, ''name'', {value: name, configurable: true});
};
/* __________________________________________________________________________ */
let myFunc = function oldName () {};
console.log(myFunc.name); // oldName
myFunc = nameFunction(myFunc, ''newName'');
console.log(myFunc.name); // newName
Nota: configurable
se establece en true
para que coincida con la especificación ES2015 estándar para Function.name 1
Esto ayudó especialmente a evitar un error en el paquete web similar a este .
Actualización: estaba pensando en publicar esto como un paquete npm, pero este paquete de sindresorhus hace exactamente lo mismo.
function myFunction() {
console.log(''It works!'');
}
var name = ''myFunction'';
window[name].call();