Имя динамической функции в javascript? - программирование
Подтвердить что ты не робот

Имя динамической функции в javascript?

У меня есть это:

this.f = function instance(){};

Я хотел бы иметь это:

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

Ответ 1

Обновление

Как уже упоминалось, это не самое быстрое и рекомендуемое решение. Решение Marcosc ниже - это путь.

Вы можете использовать eval:

var code = "this.f = function " + instance + "() {...}";
eval(code);

Ответ 2

Это будет в основном делать это на самом простом уровне:

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

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

Если вы хотите получить больше фантазии, у меня есть статья о " Динамические имена функций в JavaScript".

Ответ 4

В последних версиях вы можете сделать

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"

Ответ 5

Я думаю, что большинство предложений здесь субоптимальные, используя eval, hacky solutions или wrappers. Начиная с ES2015 имена выводятся из синтаксической позиции для переменных и свойств.

Так что все будет хорошо:

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

Сопротивляйтесь соблазну создавать именованные функции фабричных методов, так как вы не сможете передавать функцию извне и модифицировать ее в синтаксическую позицию, чтобы вывести ее имя. Тогда это уже слишком поздно. Если вам это действительно нужно, вам нужно создать обертку. Кто-то сделал это здесь, но это решение не работает для классов (которые также являются функциями).

Здесь был написан более подробный ответ со всеми описанными вариантами: fooobar.com/questions/116353/...

Ответ 6

Синтаксис 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.

Ответ 7

Самый проголосовавший ответ уже определил тело функции [String]. Я искал решение для переименования уже объявленного имени функции, и, наконец, после часа борьбы я справился с этим. Это:

  • принимает объявленную функцию alredy
  • анализирует его на [String] с помощью метода .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){...}

Ответ 8

Что насчет

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

Единственным недостатком является то, что функция в методе toSource не указывает имя. Это обычно только проблема для отладчиков.

Ответ 9

Для установки имени существующей анонимной функции:
(На основе ответа @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

Демо

Примечание: не делайте этого; /

Ответ 10

Динамические методы объекта могут быть созданы с использованием Object Literal Extensions, предоставленных 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);

Результат выполнения приведенного выше кода:

"called method instance: foo"
"called method instance: bar"
Object {
  "instance: bar": [Function anonymous],
  "instance: foo": [Function anonymous]
}

Ответ 11

Спасибо, Маркоск! Основываясь на его ответе, если вы хотите переименовать любую функцию, используйте это:

// 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)
}

Ответ 12

Эта функция утилиты объединяет несколько функций в одну (с использованием пользовательского имени), только требование состоит в том, что при запуске и окончании его совпадающих функций функции будут правильно "новыми".

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

Ответ 13

Есть два способа достичь этого, и у них есть свои плюсы и минусы.


name определение свойства

Определение неизменяемого name свойства для функции.

Pros

  • Каждый символ доступен для имени. (например, () 全 {}/1/얏호/ :D #GO(@*#%! /*)

Против

  • Имя синтаксиса функции ( "экспрессивное" ) может не соответствовать его значению свойства name.

Оценка выражения функции

Создание именованной функции выражение и оценка с помощью конструктора Function.

Pros

  • Имя синтаксиса функции ( "экспрессивное" ) всегда соответствует его значению свойства name.

Против

  • Белые пространства (и т.д.) недоступны для имени.
  • Expression-injectable (например, для ввода (){}/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

Ответ 14

Мне повезло в объединении ответа Даррена и ответа кернетикоса.

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

Ответ 15

Если вы хотите иметь динамическую функцию, такую как функция __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
})()

Ответ 16

Я много боролся с этим вопросом. Решение @Albin работало как шарм при разработке, но не работало, когда я перешел на производство. После некоторой отладки я понял, как добиться того, что мне нужно. Я использую ES6 с CRA (create-реакции-приложение), что означает, что он в комплекте с 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 name I need.
          // Note that it does not create the function, it 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);
          }
        }
      }
    }
  }
}

Ответ 17

function myFunction() {
    console.log('It works!');
}

var name = 'myFunction';

window[name].call();

Ответ 18

Вы были рядом:

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

Ответ 19

Возможно, я пропустил здесь очевидное, но что не так, просто добавив имя? функции вызываются независимо от их имени. имена используются только для выяснения причин. если вы назначаете его переменной, а в области видимости ее можно вызвать. происходит случай, когда вы выполняете переменную, которая является функцией. если у вас должно быть имя по причинам идентификации при отладке, вставьте его между функцией ключевого слова и открывающей скобкой.

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

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

Ответ 20

Это решение BEST, лучше new Function('return function name(){}')().

Eval - это самое быстрое решение:

введите описание изображения здесь

var name = 'FuncName'
var func = eval("(function " + name + "(){})")