Tengo esto:
this.f = function instance(){};
Me gustaría tener esto:
this.f = function ["instance:" + a](){};
javascript
function
Totty.js
fuente
fuente
this["instance"] = function() { }
this["instance" + a] = function() { }
. Eso no me quedó claro.Respuestas:
actualizar
Como han mencionado otros, 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);
fuente
eval()
(elFunction
constructor lo hace adentro).Esto básicamente lo hará al 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 desea ser más sofisticado, he escrito un artículo sobre " Nombres de funciones dinámicas en JavaScript ".
fuente
eval
para evaluar el javascript, lo que abre su código a una gran cantidad de vulnerabilidades.Puede utilizar 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});
fuente
function fn()
,fn
siendo el nombre original. Extraño.En motores recientes, puede 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"
fuente
Object.defineProperty(func, 'name', {value: name})
mi propio código, ya que creo que es un poco más natural y comprensible.{[expr]: val}
es un inicializador de objeto (como es un objeto JSON) dondeexpr
hay alguna expresión; lo que sea que evalúe es la clave.{myFn (..){..} }
es la abreviatura de{myFn: function myFn(..){..} }
. Tenga en cuenta quefunction myFn(..) {..}
se puede usar como una expresión como una función anónima, solomyFn
tendría un nombre. El último[name]
es simplemente acceder al miembro del objeto (comoobj.key
oobj['key']
)....
es el operador de propagación. (Fuente principal: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )this
. Por ejemploobj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
, no funcionará. ¡Puedes editar tu respuesta y usarlafunction nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
en su lugar!Creo que la mayoría de las sugerencias aquí son subóptimas, al usar eval, soluciones hacky o envoltorios. A partir de ES2015, los nombres se infieren 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 con nombre, 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).
Aquí se ha escrito una respuesta mucho más detallada con todas las variantes descritas: https://stackoverflow.com/a/9479081/633921
fuente
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.
fuente
La sintaxis
function[i](){}
implica un objeto con valores de propiedades que son funciones,function[]
, indexados 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]
conservará la identificación del nombre de la función. Consulte las notas a continuación sobre:
.Entonces,
javascript: alert( new function(a){ this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a] }("A") . toSource() );
se muestra
({f:(function () {})})
en FireFox.(Esta es casi la misma idea que esta solución , solo que usa un objeto genérico y ya no llena directamente el objeto de la ventana con las funciones).
Este método rellena explícitamente el entorno con
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 hace
f
referencia a unanonymous function
y noinstance: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 */
solo muestra
({f:(function instanceA() {})})
:
el javascriptfunction instance:a(){}
.eval
.Lo siguiente no es necesariamente problemático,
instanceA
función no está disponible directamente para su uso comoinstanceA()
y por eso es mucho más consistente con el contexto del problema original.
Dadas 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 tanto como sea posible.
fuente
(name => ({[name]:function(){}})[name])('test')
funciona pero(name => {var x={}; x[name] = function(){}; return x[name];})('test')
noLa respuesta más votada ya tiene el cuerpo de función [String] definido. Estaba buscando la solución para cambiar el nombre de la función ya declarada y, finalmente, después de una hora de lucha, lo resolví. Eso:
.toString()
métodofunction
y(
new Function()
constructorfunction 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){...}
fuente
Los métodos dinámicos de un objeto se pueden crear utilizando las Extensiones Literales de Objeto proporcionadas 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] }
fuente
o={}; o[name]=(()=>{})
lugar defunction <<name>>(){}
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
Demo .
Nota : No lo hagas; /
fuente
Hay dos métodos para lograrlo y tienen sus pros y sus contras.
name
definición de propiedadDefinición de
name
propiedad inmutable de una función.Pros
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)Contras
name
valor de propiedad.Evaluación de expresión de función
Hacer una expresión de función nombrada y evaluarla con constructor.
Function
Pros
name
valor de propiedad.Contras
(){}/1//
, la expresión esreturn function (){}/1//() {}
, da enNaN
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
fuente
Si desea tener una función dinámica como la
__call
función en PHP, puede usar Proxies.const target = {}; const handler = { get: function (target, name) { return (myArg) => { return new Promise(resolve => setTimeout(() => resolve('some' + myArg), 600)) } } }; const proxy = new Proxy(target, handler); (async function() { const result = await proxy.foo('string') console.log('result', result) // 'result somestring' after 600 ms })()
fuente
Puede utilizar el nombre de función dinámica y parámetros como este.
1) Definir la función Separar y llamarla
let functionName = "testFunction"; let param = {"param1":1 , "param2":2}; var func = new Function( "return " + functionName )(); func(param); function testFunction(params){ alert(params.param1); }
2) Definir el código de función dinámico
let functionName = "testFunction(params)"; let param = {"param1":"1" , "param2":"2"}; let functionBody = "{ alert(params.param1)}"; var func = new Function( "return function " + functionName + functionBody )(); func(param);
fuente
¡Gracias Marcosc! Sobre la base de su respuesta, si desea cambiar el nombre de 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) }
fuente
Esta función de utilidad fusiona múltiples funciones en una (usando un nombre personalizado), el único requisito es que las funciones proporcionadas estén correctamente "alineadas" al principio 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
fuente
Tuve mejor suerte en la combinación de la respuesta de Darren y 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
está configurado paratrue
coincidir con la especificación estándar ES2015 para Function.name 1Esto ayudó especialmente a solucionar un error en Webpack similar a este .
Actualización: estaba pensando en publicar esto como un paquete npm, pero este paquete de sindresorhus hace exactamente lo mismo.
fuente
Luché mucho con este problema. La solución @Albin funcionó de maravilla durante el desarrollo, pero no funcionó cuando la cambié a producción. Después de algunas depuraciones, me di cuenta de cómo lograr lo que necesitaba. Estoy usando ES6 con CRA (create-react-app), lo que significa que está incluido en Webpack.
Digamos que tiene un archivo que exporta las funciones que necesita:
myFunctions.js
export function setItem(params) { // ... } export function setUser(params) { // ... } export function setPost(params) { // ... } export function setReply(params) { // ... }
Y necesita llamar dinámicamente a estas funciones en otro lugar:
myApiCalls.js
import * as myFunctions from 'path_to/myFunctions'; /* note that myFunctions is imported as an array, * which means its elements can be easily accessed * using an index. You can console.log(myFunctions). */ function accessMyFunctions(res) { // lets say it receives an API response if (res.status === 200 && res.data) { const { data } = res; // I want to read all properties in data object and // call a function based on properties names. for (const key in data) { if (data.hasOwnProperty(key)) { // you can skip some properties that are usually embedded in // a normal response if (key !== 'success' && key !== 'msg') { // I'm using a function to capitalize the key, which is // used to dynamically create the function's name I need. // Note that it does not create the function, it's just a // way to access the desired index on myFunctions array. const name = `set${capitalizeFirstLetter(key)}`; // surround it with try/catch, otherwise all unexpected properties in // data object will break your code. try { // finally, use it. myFunctions[name](data[key]); } catch (error) { console.log(name, 'does not exist'); console.log(error); } } } } } }
fuente
la mejor manera es crear un objeto con una lista de funciones dinámicas como:
const USER = 'user'; const userModule = { [USER + 'Action'] : function () { ... }, [USER + 'OnClickHandler'] : function () { ... }, [USER + 'OnCreateHook'] : function () { ... }, }
fuente
function myFunction() { console.log('It works!'); } var name = 'myFunction'; window[name].call();
fuente
Puede que me esté perdiendo lo obvio aquí, pero ¿qué tiene de malo 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 llamar. Lo que sucede es que estás ejecutando una variable que resulta ser una función. si debe tener un nombre por motivos de identificación al depurar, 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 un shim externo renombrado, que también puede pasar a un envoltorio externo, si no desea ensuciar el espacio de nombres circundante. Si desea crear dinámicamente la función a partir de cadenas (lo que hacen la mayoría de estos ejemplos), es trivial cambiar el nombre de la fuente para hacer lo que desee. Sin embargo, si desea cambiar el nombre de las funciones existentes sin afectar su funcionalidad cuando se llaman en otro lugar, una corrección 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};
fuente
name
es útil, ya que ahora se infiere de la variable y las propiedades. También se usa en seguimientos de pila. Ejvar fn = function(){}; console.log(fn.name)
. Es inmutable, por lo que no puede cambiarlo más tarde. Si escribe un método de fábrica que nombra todas las funcionesfn
, esto dificultará la depuración.Estabas cerca:
this["instance_" + a] = function () {...};
{...};
fuente
Esta es la MEJOR solución, mejor que
new Function('return function name(){}')()
.Eval es la solución más rápida:
var name = 'FuncName' var func = eval("(function " + name + "(){})")
fuente