私はこれを持っています:
this.f = function instance(){};
私はこれが欲しいです:
this.f = function ["instance:" + a](){};
私はこれを持っています:
this.f = function instance(){};
私はこれが欲しいです:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }
。それは私にはわかりませんでした。
回答:
他の人が述べたように、これは最速でも最も推奨される解決策でもありません。以下のMarcoscのソリューションがその方法です。
evalを使用できます:
var code = "this.f = function " + instance + "() {...}";
eval(code);
eval()
(Function
コンストラクターが内部でそれを行います)。
これは基本的に最も単純なレベルでそれを行います:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
もっと凝ったものにしたい場合は、「JavaScriptの動的関数名」に関する記事を書いています。
MDN JavaScriptリファレンス[1]に記載されているように、Object.definePropertyを使用できます。
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
function fn()
、fn
元の名前であること。奇妙な。
最近のエンジンでは、
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})
ますが、もう少し自然で理解しやすいと思うので、自分のコードで使用し始めました。
{[expr]: val}
はオブジェクト初期化子(JSONオブジェクトと同様)であり、ここexpr
でいくつかの式があります。それが評価するものは何でも鍵です。{myFn (..){..} }
の省略形です{myFn: function myFn(..){..} }
。function myFn(..) {..}
匿名関数と同じように式として使用できることに注意してくださいmyFn
。名前だけがあります。最後[name]
は、オブジェクトのメンバーにアクセスすることです(obj.key
またはのようにobj['key']
)。...
スプレッド演算子です。(メイン・ソース:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...)
this
。たとえば、機能しobj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
ません。あなたはあなたの答えを編集してfunction nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
代わりに使うことができます!
ここでのほとんどの提案は、評価、ハッキーなソリューション、またはラッパーを使用することにより、最適ではないと思います。ES2015の時点では、名前は変数とプロパティの構文上の位置から推測されます。
したがって、これは問題なく機能します。
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
名前付き関数ファクトリメソッドを作成したいという誘惑に抵抗してください。外部から関数を渡して、その名前を推測するために構文上の位置に組み込むことができないためです。それならもう手遅れです。本当に必要な場合は、ラッパーを作成する必要があります。誰かがここでそれをしましたが、その解決策はクラス(関数でもあります)では機能しません。
概説されているすべてのバリアントを含むはるかに詳細な回答がここに書かれています:https://stackoverflow.com/a/9479081/633921
どうですか
this.f = window["instance:" + a] = function(){};
唯一の欠点は、toSourceメソッドの関数が名前を示さないことです。これは通常、デバッガーの問題にすぎません。
構文は、名前でインデックス付けされたfunction[i](){}
関数、であるプロパティ値を持つオブジェクトを意味します。
したがって。function[]
[i]
{"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]
関数名の識別を保持します。については、以下の注を参照してください:
。
そう、
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
({f:(function () {})})
FireFoxに表示されます。
(これはこのソリューションとほぼ同じアイデアですが、汎用オブジェクトを使用し、ウィンドウオブジェクトに関数を直接入力しなくなりました。)
このメソッドは、環境にinstance:x
。を明示的に設定します。
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
ディスプレイ
({f:(function () {})})
そして
function () {
}
プロパティ関数f
はanonymous function
ではなくを参照しますがinstance:x
、このメソッドはこのソリューションに関するいくつかの問題を回避します。
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
表示のみ
({f:(function instanceA() {})})
:
ていると、JavaScriptがfunction instance:a(){}
無効になります。eval
ます。以下は必ずしも問題ではありません、
instanceA
機能は、次のように直接使用することはできません。instanceA()
そのため、元の問題のコンテキストとはるかに一致しています。
これらの考慮事項を考えると、
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
OPの例のセマンティクスと構文を可能な限り使用して、グローバルコンピューティング環境を維持します。
(name => ({[name]:function(){}})[name])('test')
機能しますが(name => {var x={}; x[name] = function(){}; return x[name];})('test')
機能しません
最も投票された回答は、すでに定義されている[String]関数本体を持っています。すでに宣言されている関数の名前の名前を変更するソリューションを探していましたが、1時間苦労した後、ついに対処しました。それ:
.toString()
メソッドを使用して[文字列]に解析しますfunction
と、(
new 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){...}
オブジェクトの動的メソッドは、ECMAScript 2015(ES6)によって提供されるObject LiteralExtensionsを使用して作成できます。
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);
上記のコードを実行した結果は次のとおりです。
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
o={}; o[name]=(()=>{})
ではなくfunction <<name>>(){}
既存の無名関数の名前を設定する場合:
(@ 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
デモ。
注:それをしないでください; /
これを実現するには2つの方法があり、それぞれに長所と短所があります。
name
プロパティの定義関数の不変name
プロパティを定義します。
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)name
プロパティ値と一致しない場合があります。名前付き関数式を作成し、コンストラクターで評価しFunction
ます。
name
プロパティ値に対応しています。(){}/1//
、入力の場合、式はreturn function (){}/1//() {}
、NaN
関数の代わりに与えます)。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
__call
PHPの関数のような動的関数が必要な場合は、プロキシを使用できます。
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
})()
このような動的関数名とパラメーターを使用できます。
1)関数Separateを定義し、それを呼び出します
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2)機能コードを動的に定義する
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);
このユーティリティ関数は、(カスタム名を使用して)複数の関数を1つにマージします。唯一の要件は、提供された関数がスクープの開始時と終了時に適切に「新しい行」であるということです。
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
ダレンの答えと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
注:configurable
に設定されているtrue
Function.nameための標準ES2015の仕様に合わせて、1
これは、特にに類似のWebPACKでエラーが周りを取得して助けたこれを。
更新:これをnpmパッケージとして公開することを考えていましたが、sindresorhusのこのパッケージはまったく同じことを行います。
私はこの問題で多くの苦労をしました。@Albinソリューションは、開発中は魅力のように機能しましたが、本番環境に変更すると機能しませんでした。いくつかのデバッグの後、私は必要なことを達成する方法に気づきました。私はCRA(create-react-app)でES6を使用しています。これは、Webpackにバンドルされていることを意味します。
必要な機能をエクスポートするファイルがあるとします。
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
そして、これらの関数を他の場所で動的に呼び出す必要があります。
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);
}
}
}
}
}
}
次のような動的関数のリストを使用してオブジェクトを作成するのが最善の方法です。
const USER = 'user';
const userModule = {
[USER + 'Action'] : function () { ... },
[USER + 'OnClickHandler'] : function () { ... },
[USER + 'OnCreateHook'] : function () { ... },
}
ここで明らかなことを見逃しているかもしれませんが、名前を追加するだけで何が問題になりますか?関数は、名前に関係なく呼び出されます。名前は、スコープの理由で使用されています。それを変数に割り当て、スコープ内にある場合は、呼び出すことができます。たまたま関数である変数を実行していることが起こります。デバッグ時に識別上の理由で名前が必要な場合は、キーワード関数と開始中括弧の間に名前を挿入します。
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
別のアプローチは、関数を外側の名前が変更されたシムでラップすることです。周囲の名前空間を汚したくない場合は、外側のラッパーに渡すこともできます。文字列から実際に動的に関数を作成したい場合(これらの例のほとんどはそうです)、ソースの名前を変更して必要なことを行うのは簡単です。ただし、他の場所で呼び出されたときに機能に影響を与えずに既存の関数の名前を変更したい場合は、シムがそれを実現する唯一の方法です。
(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
は、変数とプロパティから推測されるようになったので便利です。スタックトレースでも使用されます。例var fn = function(){}; console.log(fn.name)
。不変なので、後で変更することはできません。すべての関数に名前を付けるファクトリメソッドをfn
作成すると、デバッグが難しくなります。
this["instance"] = function() { }