Существует ли какой-либо неэвариантный способ создания функции с определением времени выполнения? - программирование
Подтвердить что ты не робот

Существует ли какой-либо неэвариантный способ создания функции с определением времени выполнения?

Есть ли способ создать функцию с реальным именем, определенным во время выполнения без использования eval, и используя только чистый JavaScript? (Таким образом, нет сгенерированных элементов script, поскольку они специфичны для среды браузера [и во многих отношениях были бы eval в масках в любом случае], без использования нестандартных функций одного конкретного механизма JavaScript и т.д.)

Обратите внимание, что я специально не спрашиваю об анонимных функциях, на которые ссылаются переменные или свойства с именами, например:

// NOT this
var name = /* ...come up with the name... */;
var obj = {};
obj[name] = function() { /* ... */ };

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

4b9b3361

Ответ 1

Ответ для ECMAScript 2015+ (он же "ES6"):

Да. Начиная с ES2015, функция, созданная выражением анонимной функции, назначенным свойству объекта, получает имя этого свойства объекта. Это реализовано во всех современных браузерах, хотя Edge и Safari не используют имя в трассировке стека. Мы можем использовать это в сочетании с другой функцией ES2015 (имена вычисляемых свойств), чтобы называть функции без new Function или eval.

В ES2015 это создает функцию с именем "foo ###", где ### имеет 1-3 цифры:

const dynamicName = "foo" + Math.floor(Math.random() * 1000);
const obj = {
  [dynamicName]() {
    throw new Error();
  }
};
const f = obj[dynamicName];
// See its 'name' property
console.log("Function 'name' property: " + f.name + " (see compatibility note)");
// We can see whether it has a name in stack traces via an exception
try {
  f();
} catch (e) {
  console.log(e.stack);
}

Ответ 2

Вот функция полезности, с которой я пришел некоторое время назад. Он использует конструктор Function, как указано в замечании @T.J.Crowder, но улучшает его недостатки и позволяет мелкозернистый контроль над областью действия новой функции.

function NamedFunction(name, args, body, scope, values) {
    if (typeof args == "string")
        values = scope, scope = body, body = args, args = [];
    if (!Array.isArray(scope) || !Array.isArray(values)) {
        if (typeof scope == "object") {
            var keys = Object.keys(scope);
            values = keys.map(function(p) { return scope[p]; });
            scope = keys;
        } else {
            values = [];
            scope = [];
        }
    }
    return Function(scope, "function "+name+"("+args.join(", ")+") {\n"+body+"\n}\nreturn "+name+";").apply(null, values);
};

Это позволяет вам быть аккуратным и избегать полного доступа к вашей области с помощью eval, например. в приведенном выше сценарии:

var f = NamedFunction("fancyname", ["hi"], "display(hi);", {display:display});
f.toString(); // "function fancyname(hi) {
              // display(hi);
              // }"
f("Hi");