Eu tenho isto:
this.f = function instance(){};
Eu gostaria de ter isto:
this.f = function ["instance:" + a](){};
javascript
function
Totty.js
fonte
fonte
this["instance"] = function() { }
this["instance" + a] = function() { }
. Isso não ficou claro para mim.Respostas:
atualizar
Como outros mencionaram, esta não é a solução mais rápida nem a mais recomendada. A solução de Marcosc abaixo é o caminho a percorrer.
Você pode usar eval:var code = "this.f = function " + instance + "() {...}"; eval(code);
fonte
eval()
(oFunction
construtor faz isso por dentro).Isso basicamente fará no nível mais simples:
"use strict"; var name = "foo"; var func = new Function( "return function " + name + "(){ alert('sweet!')}" )(); //call it, to test it func();
Se você quiser ser mais sofisticado, escrevi um artigo sobre " Nomes de funções dinâmicas em JavaScript ".
fonte
eval
para avaliar o javascript - abrindo assim o seu código para uma série de vulnerabilidades.Você pode usar Object.defineProperty conforme observado na Referência de JavaScript MDN [1]:
var myName = "myName"; var f = function () { return true; }; Object.defineProperty(f, 'name', {value: myName, writable: false});
fonte
function fn()
,fn
sendo o nome original. Esquisito.Em motores recentes, você pode fazer
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"
fonte
Object.defineProperty(func, 'name', {value: name})
meu próprio código, pois acho que talvez seja um pouco mais natural e compreensível.{[expr]: val}
é um inicializador de objeto (como é um objeto JSON) ondeexpr
está alguma expressão; tudo o que for avaliado é a chave.{myFn (..){..} }
é uma abreviação de{myFn: function myFn(..){..} }
. Observe quefunction myFn(..) {..}
pode ser usada como uma expressão, assim como uma função anônima, apenasmyFn
teria um nome. O último[name]
é apenas acessar o membro do objeto (assim comoobj.key
ouobj['key']
)....
é o operador de propagação. (Fonte principal: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )this
. Por exemploobj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
, não funciona. Você pode editar sua resposta e usarfunction nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
!Eu acho que a maioria das sugestões aqui são subótimas, usando eval, soluções hacky ou invólucros. A partir do ES2015, os nomes são inferidos da posição sintática para variáveis e propriedades.
Então, isso vai funcionar muito bem:
const name = 'myFn'; const fn = {[name]: function() {}}[name]; fn.name // 'myFn'
Resista à tentação de criar métodos de fábrica de função nomeados, pois você não seria capaz de passar a função de fora e retrofit para a posição sintática para inferir seu nome. Então já é tarde demais. Se você realmente precisa disso, deve criar um invólucro. Alguém fez isso aqui, mas essa solução não funciona para classes (que também são funções).
Uma resposta muito mais detalhada com todas as variantes descritas foi escrita aqui: https://stackoverflow.com/a/9479081/633921
fonte
A respeito
this.f = window["instance:" + a] = function(){};
A única desvantagem é que a função em seu método toSource não indica um nome. Normalmente, isso é um problema apenas para depuradores.
fonte
A sintaxe
function[i](){}
implica em um objeto com valores de propriedade que são funçõesfunction[]
,, indexados pelo nome[i]
,.Assim
{"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á a identificação do nome da função. Veja as notas abaixo a respeito:
.Então,
javascript: alert( new function(a){ this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a] }("A") . toSource() );
exibe
({f:(function () {})})
no FireFox.(Esta é quase a mesma ideia que esta solução , só que usa um objeto genérico e não preenche mais diretamente o objeto de janela com as funções.)
Este método preenche explicitamente o ambiente com
instance:x
.javascript: alert( new function(a){ this.f=eval("instance:"+a+"="+function(){}) }("A") . toSource() ); alert(eval("instance:A"));
monitores
({f:(function () {})})
e
function () { }
Embora a função de propriedade
f
faça referência a umanonymous function
e nãoinstance:x
, este método evita vários problemas com essa solução .javascript: alert( new function(a){ eval("this.f=function instance"+a+"(){}") }("A") . toSource() ); alert(instanceA); /* is undefined outside the object context */
exibe apenas
({f:(function instanceA() {})})
:
torna o javascriptfunction instance:a(){}
inválido.eval
.O seguinte não é necessariamente problemático,
instanceA
função não está diretamente disponível para uso comoinstanceA()
e, portanto, é muito mais consistente com o contexto do problema original.
Dadas essas considerações,
this.f = {"instance:1": function instance1(){}, "instance:2": function instance2(){}, "instance:A": function instanceA(){}, "instance:Z": function instanceZ(){} } [ "instance:" + a ]
mantém o ambiente de computação global com a semântica e sintaxe do exemplo de OP tanto quanto possível.
fonte
(name => ({[name]:function(){}})[name])('test')
funciona, mas(name => {var x={}; x[name] = function(){}; return x[name];})('test')
nãoA resposta mais votada já possui o corpo da função [String] definido. Eu estava procurando a solução para renomear o nome da função já declarada e finalmente após uma hora de luta resolvi o problema. Isto:
.toString()
métodofunction
e(
new Function()
construtorfunction 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){...}
fonte
Os métodos dinâmicos de um objeto podem ser criados usando as extensões literais de objeto fornecidas pelo 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);
O resultado da execução do código acima é:
"called method instance: foo" "called method instance: bar" Object { "instance: bar": [Function anonymous], "instance: foo": [Function anonymous] }
fonte
o={}; o[name]=(()=>{})
vez defunction <<name>>(){}
Para definir o nome de uma função anônima existente :
(Com base na resposta 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 : Não faça isso; /
fonte
Existem dois métodos para conseguir isso, e eles têm seus prós e contras.
name
definição de propriedadeDefinindo a
name
propriedade imutável de uma função.Prós
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)Contras
name
valor de propriedade.Avaliação da expressão de função
Fazendo uma expressão de função nomeada e avaliando -a com o construtor.
Function
Prós
name
valor de propriedade.Contras
(){}/1//
, a expressão éreturn function (){}/1//() {}
, dá emNaN
vez de uma função.).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
fonte
Se você deseja ter uma função dinâmica como a
__call
função em PHP, você pode 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 })()
fonte
Você pode usar o nome da função dinâmica e parâmetros como este.
1) Defina a função Separate e chame-a
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 código de função 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);
fonte
Obrigada Marcosc! Com base na resposta dele, se você quiser renomear qualquer função, use o seguinte:
// 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) }
fonte
Esta função de utilitário mescla várias funções em uma (usando um nome personalizado), o único requisito é que as funções fornecidas sejam devidamente "alinhadas" no início e no final de seu furo.
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
fonte
Eu tive melhor sorte na combinação de resposta de Darren e resposta das 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
é definido paratrue
corresponder à especificação ES2015 padrão para Function.name 1Isso ajudou especialmente a contornar um erro no Webpack semelhante a este .
Atualização: eu estava pensando em publicar isso como um pacote npm, mas este pacote do sindresorhus faz exatamente a mesma coisa.
fonte
Eu lutei muito com esse problema. A solução @Albin funcionou perfeitamente durante o desenvolvimento, mas não funcionou quando mudei para produção. Depois de algumas depurações, percebi como conseguir o que precisava. Estou usando o ES6 com CRA (criar-reagir-app), o que significa que é empacotado pelo Webpack.
Digamos que você tenha um arquivo que exporta as funções de que precisa:
myFunctions.js
export function setItem(params) { // ... } export function setUser(params) { // ... } export function setPost(params) { // ... } export function setReply(params) { // ... }
E você precisa chamar dinamicamente essas funções em outro 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); } } } } } }
fonte
a melhor maneira é criar um objeto com lista de funções dinâmicas como:
const USER = 'user'; const userModule = { [USER + 'Action'] : function () { ... }, [USER + 'OnClickHandler'] : function () { ... }, [USER + 'OnCreateHook'] : function () { ... }, }
fonte
function myFunction() { console.log('It works!'); } var name = 'myFunction'; window[name].call();
fonte
Posso estar perdendo o óbvio aqui, mas o que há de errado em apenas adicionar o nome? as funções são chamadas independentemente de seu nome. nomes são usados apenas por razões de escopo. se você atribuí-lo a uma variável e está no escopo, pode ser chamado. O que acontece é que você está executando uma variável que por acaso é uma função. se você deve ter um nome por motivos de identificação ao depurar, insira-o entre a função de palavra-chave e a chave de abertura.
var namedFunction = function namedFunction (a,b) {return a+b}; alert(namedFunction(1,2)); alert(namedFunction.name); alert(namedFunction.toString());
uma abordagem alternativa é envolver a função em um shim externo renomeado, que você também pode passar para um wrapper externo, se não quiser sujar o namespace circundante. se você deseja realmente criar dinamicamente a função a partir de strings (o que a maioria desses exemplos faz), é trivial renomear a fonte para fazer o que você deseja. se, no entanto, você deseja renomear funções existentes sem afetar sua funcionalidade quando chamadas em outro lugar, um shim é a única maneira de conseguir isso.
(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};
fonte
name
é útil, pois agora é inferido de variáveis e propriedades. Também é usado em rastreamentos de pilha. Exvar fn = function(){}; console.log(fn.name)
. É imutável, então você não pode alterá-lo depois. Se você escrever um método de fábrica que nomeie todas as funçõesfn
, isso tornará a depuração mais difícil.Você estava perto de:
this["instance_" + a] = function () {...};
{...};
fonte
Esta é a MELHOR solução, melhor então
new Function('return function name(){}')()
.Eval é a solução mais rápida:
var name = 'FuncName' var func = eval("(function " + name + "(){})")
fonte