Aku punya ini:
this.f = function instance(){};
Saya ingin memiliki ini:
this.f = function ["instance:" + a](){};
Aku punya ini:
this.f = function instance(){};
Saya ingin memiliki ini:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }. Itu tidak jelas bagi saya.
Jawaban:
Seperti yang disebutkan orang lain, ini bukan solusi tercepat atau paling direkomendasikan. Solusi Marcosc di bawah ini adalah cara yang harus dilakukan.
Anda dapat menggunakan eval:
var code = "this.f = function " + instance + "() {...}";
eval(code);
eval()( Functionkonstruktor melakukannya di dalam).
Ini pada dasarnya akan melakukannya di tingkat yang paling sederhana:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
Jika Anda ingin lebih mewah, saya telah menulis artikel tentang " Nama fungsi dinamis dalam JavaScript ".
evaluntuk mengevaluasi javascript - sehingga membuka kode Anda ke banyak kerentanan.
Anda dapat menggunakan Object.defineProperty seperti yang tercantum dalam Referensi JavaScript MDN [1]:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
function fn(), fnmenjadi nama aslinya. Aneh.
Di mesin terbaru, Anda bisa melakukannya
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})kode saya sendiri, karena menurut saya kode ini mungkin sedikit lebih alami dan mudah dipahami.
{[expr]: val}adalah penginisialisasi objek (seperti objek JSON) di mana exprbeberapa ekspresi; apa pun yang dinilai adalah kuncinya. {myFn (..){..} }adalah singkatan dari {myFn: function myFn(..){..} }. Perhatikan bahwa function myFn(..) {..}bisa digunakan sebagai ekspresi seperti fungsi anonim, hanya myFnakan memiliki nama. Yang terakhir [name]hanya mengakses anggota objek (seperti obj.keyatau obj['key']). ...adalah operator penyebaran. (Sumber utama: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
this. Misalnya obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();tidak akan berhasil. Anda dapat mengedit jawaban Anda dan menggunakannya function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }!
Saya pikir sebagian besar saran di sini kurang optimal, dengan menggunakan eval, solusi hacky, atau pembungkus. Sejak ES2015, nama disimpulkan dari posisi sintaksis untuk variabel dan properti.
Jadi ini akan bekerja dengan baik:
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
Tahan godaan untuk membuat metode pabrik fungsi bernama karena Anda tidak akan bisa meneruskan fungsi dari luar dan memasangnya kembali ke posisi sintaksis untuk menyimpulkan namanya. Maka itu sudah terlambat. Jika Anda benar-benar membutuhkannya, Anda harus membuat pembungkus. Seseorang melakukannya di sini, tetapi solusi itu tidak berfungsi untuk kelas (yang juga merupakan fungsi).
Jawaban yang jauh lebih mendalam dengan semua varian yang diuraikan telah ditulis di sini: https://stackoverflow.com/a/9479081/633921
Bagaimana dengan
this.f = window["instance:" + a] = function(){};
Satu-satunya kelemahan adalah fungsi dalam metode toSource-nya tidak akan menunjukkan nama. Itu biasanya hanya menjadi masalah bagi debugger.
Sintaksnya function[i](){}menyiratkan sebuah objek dengan nilai properti yang berfungsi function[],, diindeks dengan nama [i],.
Jadi
{"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]akan mempertahankan identifikasi nama fungsi. Lihat catatan di bawah tentang :.
Begitu,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
ditampilkan ({f:(function () {})})di FireFox.
(Ide ini hampir sama dengan solusi ini , hanya saja ia menggunakan objek generik dan tidak lagi mengisi objek jendela secara langsung dengan fungsinya.)
Metode ini secara eksplisit mengisi lingkungan dengan instance:x.
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
menampilkan
({f:(function () {})})
dan
function () {
}
Meskipun fungsi properti fmereferensikan anonymous functiondan bukan instance:x, metode ini menghindari beberapa masalah dengan solusi ini .
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
hanya menampilkan
({f:(function instanceA() {})})
:membuat javascript function instance:a(){}tidak valid.eval.Berikut ini belum tentu bermasalah,
instanceAFungsi ini tidak langsung tersedia untuk digunakan sebagaiinstanceA()dan jauh lebih konsisten dengan konteks masalah aslinya.
Dengan pertimbangan ini,
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
memelihara lingkungan komputasi global dengan semantik dan sintaks dari contoh OP sebanyak mungkin.
(name => ({[name]:function(){}})[name])('test')berfungsi tetapi (name => {var x={}; x[name] = function(){}; return x[name];})('test')tidak
Jawaban yang paling banyak dipilih telah menentukan fungsi tubuh [String]. Saya mencari solusi untuk mengganti nama nama fungsi yang sudah dideklarasikan dan akhirnya setelah satu jam berjuang, saya telah mengatasinya. Itu:
.toString() metodefunctiondan(new Function()konstruktorfunction 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){...}
Metode dinamis suatu objek dapat dibuat menggunakan Ekstensi Literal Objek yang disediakan oleh 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);
Output dari menjalankan kode di atas adalah:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
o={}; o[name]=(()=>{})daripadafunction <<name>>(){}
Untuk menyetel nama fungsi anonim yang ada :
(Berdasarkan jawaban @ 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 .
Catatan : Jangan lakukan itu; /
Ada dua metode untuk mencapai ini, dan mereka memiliki pro dan kontra.
name definisi propertiMendefinisikan properti yang tidak dapat diubahname dari suatu fungsi.
() 全 {}/1/얏호/ :D #GO(@*#%! /*)namenilai propertinya.Membuat ekspresi fungsi bernama dan mengevaluasinya dengan konstruktor.Function
namenilai propertinya.(){}/1//, ekspresinya adalah return function (){}/1//() {}, memberikan NaNalih-alih fungsi.).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
Jika Anda ingin memiliki fungsi dinamis seperti __callfungsi di PHP, Anda dapat menggunakan 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
})()
Anda dapat menggunakan Nama Fungsi Dinamis dan parameter seperti ini.
1) Tentukan fungsi Pisahkan dan panggil
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2) Tentukan dinamis kode fungsi
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);
Terima kasih Marcosc! Berdasarkan jawabannya, jika Anda ingin mengganti nama fungsi apa pun , gunakan ini:
// 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)
}
Fungsi utilitas ini menggabungkan beberapa fungsi menjadi satu (menggunakan nama kustom), satu-satunya persyaratan adalah fungsi yang disediakan "baru berjajar" dengan benar di awal dan akhir scoopnya.
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
Saya lebih beruntung dalam menggabungkan jawaban Darren dan jawaban 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
Catatan: configurablediatur agar truesesuai dengan spesifikasi ES2015 standar untuk Function.name 1
Ini sangat membantu dalam mengatasi kesalahan di Webpack yang mirip dengan ini .
Pembaruan: Saya berpikir untuk menerbitkan ini sebagai paket npm, tetapi paket dari sindresorhus ini melakukan hal yang persis sama.
Saya berjuang keras dengan masalah ini. Solusi @Albin bekerja seperti pesona saat mengembangkan, tetapi tidak berfungsi ketika saya mengubahnya ke produksi. Setelah beberapa debugging, saya menyadari bagaimana mencapai apa yang saya butuhkan. Saya menggunakan ES6 dengan CRA (create-react-app), yang berarti itu dibundel oleh Webpack.
Katakanlah Anda memiliki file yang mengekspor fungsi yang Anda butuhkan:
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
Dan Anda perlu memanggil fungsi ini secara dinamis di tempat lain:
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);
}
}
}
}
}
}
cara terbaik adalah membuat objek dengan daftar fungsi dinamis seperti:
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();
Saya mungkin melewatkan yang sudah jelas di sini, tetapi apa salahnya hanya dengan menambahkan nama? fungsi dipanggil terlepas dari namanya. nama hanya digunakan untuk alasan pelingkupan. jika Anda menugaskannya ke variabel, dan berada dalam cakupan, itu bisa dipanggil. Yang terjadi adalah Anda menjalankan variabel yang kebetulan merupakan fungsi. jika Anda harus memiliki nama untuk alasan identifikasi saat debugging, masukkan di antara fungsi kata kunci dan kurung kurawal buka.
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
pendekatan alternatif adalah membungkus fungsi dalam shim berganti nama luar, yang juga bisa Anda berikan ke pembungkus luar, jika Anda tidak ingin mengotori namespace sekitarnya. jika Anda ingin benar-benar membuat fungsi secara dinamis dari string (yang dilakukan sebagian besar contoh ini), sangat mudah untuk mengganti nama sumber untuk melakukan apa yang Anda inginkan. Namun jika Anda ingin mengganti nama fungsi yang ada tanpa memengaruhi fungsinya saat dipanggil di tempat lain, shim adalah satu-satunya cara untuk mencapainya.
(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};
nameberguna karena disimpulkan dari variabel dan properti sekarang. Ini juga digunakan dalam pelacakan tumpukan. Mis var fn = function(){}; console.log(fn.name). Ini tidak dapat diubah, jadi Anda tidak dapat mengubahnya nanti. Jika Anda menulis metode pabrik yang menamai semua fungsi fnmaka ini akan mempersulit proses debug.
this["instance"] = function() { }