Dynamiczna nazwa funkcji w javascript?

Mam to:

this.f = function instance(){};

Chciałbym mieć to:

this.f = function ["instance:" + a](){};
Author: Tim Cooper, 2011-05-06

18 answers

Update

Jak inni wspominali, nie jest to najszybsze i najbardziej zalecane rozwiązanie. rozwiązanie Marcosca poniżej{[5] } jest dobrym rozwiązaniem.

możesz użyć eval:

var code = "this.f = function " + instance + "() {...}";
eval(code);
 5
Author: Mo Valipour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:13

To w zasadzie zrobi to na najprostszym poziomie:

"use strict";
var name = "foo";
var func = new Function(
     "return function " + name + "(){ alert('sweet!')}"
)();

//call it, to test it
func();

Jeśli chcesz uzyskać więcej fantazji, mam napisany artykuł na " dynamiczne nazwy funkcji w JavaScript ".

 100
Author: Marcosc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-30 17:39:30

Możesz użyć obiektu.defineProperty jak zaznaczono w MDN JavaScript Reference [1]:

var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Description
 24
Author: Darren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-01 19:20:37

W ostatnich silnikach można zrobić

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"
 8
Author: kybernetikos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-04 15:06:16

Składnia function[i](){} implikuje obiekt z wartościami właściwości, które są funkcjami, function[], indeksowanymi przez nazwę, [i].
Tak więc
{"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] zachowa identyfikację nazwy funkcji. Patrz UWAGI poniżej dotyczące :.

Więc,

javascript: alert(
  new function(a){
    this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
  }("A") . toSource()
);

Wyświetla ({f:(function () {})}) w Firefoksie.
(Jest to prawie ten sam pomysł, co To rozwiązanie, tylko używa obiektu ogólnego i nie zapełnia bezpośrednio obiektu window funkcjami.)

Ta metoda jawnie wypełnia środowisko za pomocą instance:x.

javascript: alert(
  new function(a){
    this.f=eval("instance:"+a+"="+function(){})
  }("A") . toSource()
);
alert(eval("instance:A"));

Wyświetlacze

({f:(function () {})})

I

function () {
}

Chociaż funkcja właściwości f odwołuje się do anonymous function, a nie instance:x, ta metoda pozwala uniknąć kilku problemów ztym rozwiązaniem .

javascript: alert(
  new function(a){
    eval("this.f=function instance"+a+"(){}")
  }("A") . toSource()
);
alert(instanceA);    /* is undefined outside the object context */

Wyświetla tylko

({f:(function instanceA() {})})
  • wbudowany : sprawia, że javascript function instance:a(){} jest nieważny.
  • zamiast odniesienia, rzeczywista definicja tekstu funkcji jest analizowana i interpretowana przez eval.

Poniższe nie jest koniecznie problematyczne,

  • funkcja instanceA nie jest bezpośrednio dostępna do użycia jako instanceA()

I tak jest o wiele bardziej zgodne z oryginalnym kontekstem problemu.

Biorąc pod uwagę te rozważania,

this.f = {"instance:1": function instance1(){},
          "instance:2": function instance2(){},
          "instance:A": function instanceA(){},
          "instance:Z": function instanceZ(){}
         } [ "instance:" + a ]

Utrzymuje globalne środowisko obliczeniowe z semantyką i składnią przykładu OP w jak największym stopniu.

 3
Author: Ekim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:39

Najczęściej głosowana odpowiedź ma już zdefiniowane ciało funkcji [String]. Szukałem rozwiązania do zmiany nazwy już zadeklarowanej funkcji i w końcu po godzinie zmagań poradziłem sobie z tym. It:

  • przyjmuje zadeklarowaną funkcję
  • parsuje go do [String] za pomocą metody .toString()
  • następnie nadpisuje nazwę (nazwanej funkcji) lub dodaje nową (gdy anonimowa) pomiędzy function i (
  • następnie tworzy nowy zmiana nazwy funkcji za pomocą konstruktora 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){...}
 3
Author: Paweł,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 12:46:11

Myślę, że większość sugestii tutaj są nieoptymalne, za pomocą eval, hacky rozwiązań lub wrappers. Począwszy od ES2015 nazwy są wnioskowane z pozycji składniowej dla zmiennych i właściwości.

Więc to będzie działać dobrze:

const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'

Oprzyj się pokusie tworzenia nazwanych metod fabrycznych funkcji, ponieważ nie byłbyś w stanie przekazać funkcji z zewnątrz i zmodyfikować jej do pozycji składniowej, aby wywnioskować jej nazwę. Więc jest już za późno. Jeśli naprawdę tego potrzebujesz, musisz stwórz opakowanie. Ktoś to tutaj zrobił, ale to rozwiązanie nie działa dla klas (które są również funkcjami).

O wiele bardziej dogłębna odpowiedź ze wszystkimi opisanymi wariantami została napisana tutaj: https://stackoverflow.com/a/9479081/633921

 2
Author: Albin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 05:57:39

Do Ustawienia nazwy istniejącej funkcji anonimowej:
(Na podstawie odpowiedzi @ 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 .

Uwaga: nie rób tego; /

 2
Author: Onur Yıldırım,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 20:23:28

A co z

this.f = window["instance:" + a] = function(){};

Jedyną wadą jest to, że funkcja w metodzie toSource nie wskazuje nazwy. Zwykle jest to problem tylko dla debugerów.

 1
Author: entonio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-06 00:59:13

Dynamiczne metody obiektu mogą być tworzone przy użyciu dosłownych rozszerzeń obiektu dostarczonych przez 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);

Wynik uruchomienia powyższego kodu to:

"called method instance: foo"
"called method instance: bar"
Object {
  "instance: bar": [Function anonymous],
  "instance: foo": [Function anonymous]
}
 1
Author: Luke Schoen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-29 08:48:50

Dziękuję Marcosc! Bazując na jego odpowiedzi, jeśli chcesz zmienić nazwę dowolnej funkcji , Użyj tego:

// 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)
}
 0
Author: B T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-23 01:53:41

Ta funkcja użytkowa łączy wiele funkcji w jedną (używając niestandardowej nazwy), jedynym wymogiem jest to, aby dostarczone funkcje były prawidłowo "nowe" na początku i końcu jej miarki.

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
 0
Author: MetalGodwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-11 20:38:37

Są dwie metody, aby to osiągnąć, i mają swoje plusy i minusy.


name Definicja właściwości

Definiowanie immutable name właściwość funkcji.

Plusy

  • każdy znak jest dostępny dla nazwy. (np. () 全 {}/1/얏호/ :D #GO(@*#%! /*)

Cons

  • nazwa składniowa funkcji może nie odpowiadać jej wartości właściwości name.

Funkcja ocena ekspresji

Tworzenie nazwanej funkcji wyrażenie i ocenianie za pomocą konstruktora Function.

Plusy

  • nazwa składniowa funkcji zawsze odpowiada jej wartości właściwości name.

Cons

  • Whitespaces (and etc.) nie są dostępne dla nazwy.
  • ekspresja-iniekcja (np. Dla wejścia (){}/1// wyrażenie jest return function (){}/1//() {}, daje NaN zamiast funkcja.).

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
 0
Author: K._,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-20 10:37:43

Miałem więcej szczęścia w połączeniu odpowiedź Darrena i odpowiedź 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

Uwaga: configurable jest ustawiona na true, aby pasowała do standardowej specyfikacji ES2015 dla Function.name1

To szczególnie pomogło w obejściu błędu w Webpacku podobnego do tego .

Update: myślałem o opublikowaniu tego jako pakietu npm, ale ten pakiet od sindresorhus robi dokładnie to samo rzecz.

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
 0
Author: Scott Rudiger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-28 22:10:53
function myFunction() {
    console.log('It works!');
}

var name = 'myFunction';

window[name].call();
 -1
Author: Danilo Colasso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-05 18:18:44

Byłeś blisko:

this["instance_" + a] = function () {...};

{...};

 -1
Author: berge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-04 13:27:20

Może brakuje mi tego, co oczywiste, ale co jest złego w dodaniu nazwy? funkcje są wywoływane niezależnie od ich nazwy. nazwy są używane tylko ze względu na zasięg. jeśli przypiszesz go do zmiennej i znajduje się w zakresie, można go wywołać. hat happens jest to, że wykonujesz zmienną, która jest funkcją. jeśli podczas debugowania musisz mieć Nazwę Ze względów identyfikacyjnych, Wstaw ją między funkcję słowa kluczowego a nawias otwierający.

var namedFunction = function namedFunction (a,b) {return a+b};

alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());

An alternatywnym podejściem jest zawijanie funkcji w zewnętrzną warstwę o nazwie shim, którą można również przenieść do zewnętrznej powłoki, jeśli nie chcesz zabrudzić otaczającej przestrzeni nazw. jeśli chcesz dynamicznie tworzyć funkcję z łańcuchów znaków (co robi większość z tych przykładów), zmiana nazwy źródła jest banalna. jeśli jednak chcesz zmienić nazwy istniejących funkcji bez wpływu na ich funkcjonalność, gdy wywołane gdzie indziej, podkładka jest jedynym sposobem, aby osiągnąć to.

(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};
 -2
Author: cestmoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-27 00:40:10

To jest najlepsze rozwiązanie, lepsze niż new Function('return function name(){}')().

Eval jest najszybszym rozwiązaniem:

Tutaj wpisz opis obrazka

var name = 'FuncName'
var func = eval("(function " + name + "(){})")
 -9
Author: Maxmaxmaximus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-06 15:14:22