18 ответов:
обновление
как уже упоминалось, это не самое быстрое и не самое рекомендуемое решение. решение Marcosc ниже - это путь.
вы можете использовать eval:var code = "this.f = function " + instance + "() {...}"; eval(code);
это будет в основном делать это на самом простом уровне:
"use strict"; var name = "foo"; var func = new Function( "return function " + name + "(){ alert('sweet!')}" )(); //call it, to test it func();Если вы хотите получить больше фантазии, у меня есть написанная статья на "динамические имена функций в JavaScript".
вы можете использовать объект.defineProperty, как указано в ссылке MDN JavaScript [1]:
var myName = "myName"; var f = function () { return true; }; Object.defineProperty(f, 'name', {value: myName, writable: false});
в последних движках, вы можете сделать
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"
синтаксис
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() {})})
- встроенный
:делает javascriptfunction instance:a(){}недействительным.- вместо ссылки, фактическое определение текста функции анализируется и интерпретируется
eval.следующее Не обязательно проблематично,
- The
instanceAфункция непосредственно не доступна для использования в качествеinstanceA()и так гораздо более соответствует исходному контексту проблемы.
учитывая эти соображения,
this.f = {"instance:1": function instance1(){}, "instance:2": function instance2(){}, "instance:A": function instanceA(){}, "instance:Z": function instanceZ(){} } [ "instance:" + a ]максимально поддерживает глобальную вычислительную среду с семантикой и синтаксисом примера OP.
наиболее проголосовавший ответ получил уже определенное тело функции [String]. Я искал решение для переименования уже объявленного имени функции и, наконец, после часа борьбы я справился с этим. Это:
- принимает уже объявленную функцию
- разбирает его на [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,` ${name}`)}`))(); } //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){...}
Я думаю, что большинство предложений здесь являются неоптимальными, используя eval, hacky решения или обертки. По состоянию на ES2015 имена выводятся из синтаксической позиции для переменных и свойств.
Так это будет работать просто отлично:
const name = 'myFn'; const fn = {[name]: function() {}}[name]; fn.name // 'myFn'сопротивляйтесь искушению создать именованные методы фабрики функций, поскольку вы не сможете передать функцию извне и перестроить ее в синтаксическую позицию, чтобы вывести ее имя. Тогда уже слишком поздно. Если вам действительно нужно это, вы должны создать обертку. Кто-то сделал это здесь, но это решение не работает для классов (которые также являются функциями).
здесь был написан гораздо более глубокий ответ со всеми описанными вариантами:https://stackoverflow.com/a/9479081/633921
для установки имени существующей анонимные функции:
(На основе ответа @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демо.
Примечание: не делай этого ;/
а как же
this.f = window["instance:" + a] = function(){};единственный недостаток заключается в том, что функция в своем методе toSource не будет указывать имя. Это обычно только проблема для отладчиков.
динамические методы объекта могут быть созданы с использованием расширений литералов объектов, предоставляемых 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] }
спасибо Marcosc! Основываясь на его ответе, если вы хотите переименовать любой используйте этот:
// 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) }
эта служебная функция объединяет несколько функций в одну (используя пользовательское имя), только требование состоит в том, что предоставленные функции правильно "новые выровнены" в начале и конце его совка.
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
есть два способа добиться этого, и у них есть свои плюсы и минусы.
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
мне больше повезло в объединении Даррен!--5--> и 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соответствовать стандартным спецификациям ES2015 для Function.name1Это особенно помогло обойти ошибку в Webpack, подобную этот.
Update: я думал опубликовать это как пакет npm, но этот пакет из синдресорхус делает то же самое.
я мог бы пропустить очевидное здесь, но что плохого в том, чтобы просто добавить имя? функции вызываются, независимо от их имени. имена используются только для определения области действия. если вы назначаете его переменной, и она находится в области видимости, ее можно вызвать. hat happens - это выполнение переменной, которая является функцией. если при отладке необходимо иметь имя по причинам идентификации, вставьте его между функцией ключевого слова и открывающей фигурной скобкой.
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};

Comments