Ich habe das:
this.f = function instance(){};
Ich hätte gerne folgendes:
this.f = function ["instance:" + a](){};
Ich habe das:
this.f = function instance(){};
Ich hätte gerne folgendes:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }
. Das war mir nicht klar.
Antworten:
Wie bereits erwähnt, ist dies weder die schnellste noch die am meisten empfohlene Lösung. Die unten stehende Lösung von Marcosc ist der richtige Weg.
Sie können eval verwenden:
var code = "this.f = function " + instance + "() {...}";
eval(code);
eval()
(der Function
Konstruktor macht das im Inneren).
Dies wird es im Grunde auf der einfachsten Ebene tun:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
Wenn Sie mehr Lust haben möchten, habe ich einen Artikel über " Dynamische Funktionsnamen in JavaScript " geschrieben.
eval
das Javascript auswertet und so Ihren Code für eine Reihe von Sicherheitslücken öffnet.
Sie können Object.defineProperty wie in der MDN-JavaScript-Referenz [1] angegeben verwenden:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
function fn()
, fn
wird sie gedruckt und ist der ursprüngliche Name. Seltsam.
In neueren Motoren können Sie dies tun
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"
Object.defineProperty(func, 'name', {value: name})
meinen eigenen Code zu verwenden, da ich denke, dass er vielleicht etwas natürlicher und verständlicher ist.
{[expr]: val}
ein Objektinitialisierer (wie auch ein JSON-Objekt), in dem expr
sich ein Ausdruck befindet. Was auch immer es auswertet, ist der Schlüssel. {myFn (..){..} }
ist eine Abkürzung für {myFn: function myFn(..){..} }
. Beachten Sie, dass function myFn(..) {..}
ein Ausdruck wie eine anonyme Funktion verwendet werden kann und nur myFn
einen Namen hat. Der letzte [name]
ist nur der Zugriff auf das Mitglied des Objekts (genau wie obj.key
oder obj['key']
). ...
ist der Spread-Operator. (Hauptquelle: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
this
. Zum Beispiel obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
wird nicht funktionieren. Sie können Ihre Antwort bearbeiten und function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
stattdessen verwenden!
Ich denke, die meisten Vorschläge hier sind suboptimal, indem evale, hackige Lösungen oder Wrapper verwendet werden. Ab ES2015 werden Namen aus der syntaktischen Position für Variablen und Eigenschaften abgeleitet.
Das wird also gut funktionieren:
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
Widerstehen Sie der Versuchung, benannte Funktionsfactory-Methoden zu erstellen, da Sie die Funktion nicht von außen übergeben und an der syntaktischen Position nachrüsten können, um auf ihren Namen zu schließen. Dann ist es schon zu spät. Wenn Sie das wirklich brauchen, müssen Sie einen Wrapper erstellen. Jemand hat das hier gemacht, aber diese Lösung funktioniert nicht für Klassen (die auch Funktionen sind).
Eine ausführlichere Antwort mit allen beschriebenen Varianten wurde hier geschrieben: https://stackoverflow.com/a/9479081/633921
Die Syntax function[i](){}
impliziert ein Objekt mit Eigenschaftswerten, bei denen es sich um Funktionen handelt function[]
, die durch den Namen indiziert sind [i]
.
Also
{"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]
behält die Identifizierung des Funktionsnamens bei. Siehe Anmerkungen unten bezüglich:
.
So,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
wird ({f:(function () {})})
in FireFox angezeigt.
(Dies ist fast die gleiche Idee wie bei dieser Lösung , nur dass ein generisches Objekt verwendet wird und das Fensterobjekt nicht mehr direkt mit den Funktionen gefüllt wird.)
Diese Methode füllt die Umgebung explizit mit instance:x
.
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
Anzeigen
({f:(function () {})})
und
function () {
}
Obwohl die Eigenschaftsfunktion f
auf ein anonymous function
und nicht verweist instance:x
, vermeidet diese Methode mehrere Probleme mit dieser Lösung .
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
wird nur angezeigt
({f:(function instanceA() {})})
:
macht das Javascriptfunction instance:a(){}
ungültig.eval
.Das Folgende ist nicht unbedingt problematisch,
instanceA
Funktion steht nicht direkt zur Verfügung alsinstanceA()
und ist daher viel konsistenter mit dem ursprünglichen Problemkontext.
Angesichts dieser Überlegungen
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
pflegt die globale Computerumgebung so weit wie möglich mit der Semantik und Syntax des OP-Beispiels.
(name => ({[name]:function(){}})[name])('test')
funktioniert, (name => {var x={}; x[name] = function(){}; return x[name];})('test')
aber nicht
Die am häufigsten gewählte Antwort hat bereits den Funktionskörper [String] definiert. Ich suchte nach einer Lösung, um den Namen der bereits deklarierten Funktion umzubenennen, und schließlich habe ich mich nach einer Stunde des Kampfes damit befasst. Es:
.toString()
Methode in [String]function
und an(
new Function()
Konstruktor erstelltfunction 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){...}
Wie wäre es mit
this.f = window["instance:" + a] = function(){};
Der einzige Nachteil ist, dass die Funktion in ihrer toSource-Methode keinen Namen angibt. Das ist normalerweise nur ein Problem für Debugger.
Dynamische Methoden eines Objekts können mit den von ECMAScript 2015 (ES6) bereitgestellten Object Literal Extensions erstellt werden:
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);
Die Ausgabe des obigen Codes lautet:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
o={}; o[name]=(()=>{})
anstattfunction <<name>>(){}
So
legen Sie den Namen einer vorhandenen anonymen Funktion fest:
(Basierend auf der Antwort von @ 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 .
Hinweis : Tu es nicht; /
Es gibt zwei Methoden, um dies zu erreichen, und sie haben ihre Vor- und Nachteile.
name
EigenschaftsdefinitionDefinieren unveränderliche name
Eigenschaft einer Funktion.
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)name
Eigenschaftswert.Einen Namen Funktion Ausdruck und Auswertung mit Function
Konstruktor.
name
Eigenschaftswert.(){}/1//
der Ausdruck ist return function (){}/1//() {}
, gibt NaN
statt einer Funktion.).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
Wenn Sie eine dynamische Funktion wie die __call
Funktion in PHP haben möchten , können Sie Proxies verwenden.
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
})()
Sie können den Namen der dynamischen Funktion und solche Parameter verwenden.
1) Funktion Separate definieren und aufrufen
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2) Funktionscode dynamisch definieren
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);
Vielen Dank, Marcosc! Wenn Sie auf seiner Antwort aufbauen und eine Funktion umbenennen möchten, verwenden Sie Folgendes :
// 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)
}
Diese Dienstprogrammfunktion führt mehrere Funktionen zu einer zusammen (unter Verwendung eines benutzerdefinierten Namens). Die einzige Voraussetzung ist, dass die bereitgestellten Funktionen zu Beginn und am Ende des Bereichs ordnungsgemäß "neu gezeichnet" werden.
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
Ich hatte besseres Glück, Darrens Antwort und Kyernetikos 'Antwort zu kombinieren .
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
Hinweis: configurable
wird auf true
die Standard - ES2015 - Spezifikation für Function.name passen 1
Dies vor allem dazu beigetragen , in immer einen Fehler in Webpack ähnlich wie um diesen .
Update: Ich habe darüber nachgedacht, dies als npm-Paket zu veröffentlichen, aber dieses Paket von sindresorhus macht genau das Gleiche.
Ich hatte viel mit diesem Problem zu kämpfen. Die @ Albin-Lösung funktionierte während der Entwicklung wie ein Zauber, aber sie funktionierte nicht, als ich sie auf Produktion umstellte. Nach einigem Debuggen wurde mir klar, wie ich das erreichen konnte, was ich brauchte. Ich verwende ES6 mit CRA (Create-React-App), was bedeutet, dass es von Webpack gebündelt wird.
Nehmen wir an, Sie haben eine Datei, die die Funktionen exportiert, die Sie benötigen:
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
Und Sie müssen diese Funktionen an anderer Stelle dynamisch aufrufen:
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);
}
}
}
}
}
}
Am besten erstellen Sie ein Objekt mit einer Liste dynamischer Funktionen wie:
const USER = 'user';
const userModule = {
[USER + 'Action'] : function () { ... },
[USER + 'OnClickHandler'] : function () { ... },
[USER + 'OnCreateHook'] : function () { ... },
}
function myFunction() {
console.log('It works!');
}
var name = 'myFunction';
window[name].call();
Ich vermisse hier vielleicht das Offensichtliche, aber was ist falsch daran, nur den Namen hinzuzufügen? Funktionen werden unabhängig von ihrem Namen aufgerufen. Namen werden nur aus Gründen des Geltungsbereichs verwendet. Wenn Sie es einer Variablen zuweisen und es sich im Gültigkeitsbereich befindet, kann es aufgerufen werden. Was passiert, ist, dass Sie eine Variable ausführen, die zufällig eine Funktion ist. Wenn Sie beim Debuggen aus Identifikationsgründen einen Namen haben müssen, fügen Sie ihn zwischen der Schlüsselwortfunktion und der öffnenden Klammer ein.
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
Ein alternativer Ansatz besteht darin, die Funktion in einen äußeren umbenannten Shim zu verpacken, den Sie auch in einen äußeren Wrapper übergeben können, wenn Sie den umgebenden Namespace nicht verschmutzen möchten. Wenn Sie die Funktion tatsächlich dynamisch aus Zeichenfolgen erstellen möchten (was in den meisten dieser Beispiele der Fall ist), ist es trivial, die Quelle umzubenennen, um das zu tun, was Sie möchten. Wenn Sie jedoch vorhandene Funktionen umbenennen möchten, ohne deren Funktionalität zu beeinträchtigen, wenn Sie an anderer Stelle aufgerufen werden, ist ein Shim der einzige Weg, dies zu erreichen.
(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};
name
ist nützlich, da sie jetzt aus Variablen und Eigenschaften abgeleitet wird. Es wird auch in Stapelspuren verwendet. Bsp var fn = function(){}; console.log(fn.name)
. Es ist unveränderlich, so dass Sie es später nicht ändern können. Wenn Sie eine Factory-Methode schreiben, die alle Funktionen benennt, fn
wird das Debuggen dadurch schwieriger.
this["instance"] = function() { }