Есть ли способ получить имена параметров функции динамически?
Допустим, моя функция выглядит так:
function doSomething(param1, param2, .... paramN){
// fill an array with the parameter name and value
// some other code
}
Теперь, как мне получить список имен параметров и их значений в массиве внутри функции?
function doSomething(...args) { /*use args*/}
Ответы:
Следующая функция вернет массив имен параметров любой переданной функции.
Пример использования:
Редактировать :
С изобретением ES6 эту функцию можно отключить по умолчанию. Вот быстрый взлом, который должен работать в большинстве случаев:
Я говорю большинство случаев, потому что есть некоторые вещи, которые могут сбить его с толку
Редактировать : я также отмечаю, что vikasde также хочет значения параметров в массиве. Это уже предусмотрено в локальной переменной с именем arguments.
выдержка из https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments :
Объект аргументов не является массивом. Он похож на массив, но не имеет никаких свойств массива, кроме длины. Например, у него нет метода pop. Однако он может быть преобразован в настоящий массив:
Если доступны универсальные массивы, можно использовать следующее:
источник
var fn = function(a /* fooled you)*/,b){};
приведет к["a", "/*", "fooled", "you"]
Ниже приведен код, взятый из AngularJS, который использует технику для своего механизма внедрения зависимостей.
И вот объяснение этого взято от http://docs.angularjs.org/tutorial/step_05
источник
annotate = angular.injector.$$annotate
Вот обновленное решение, которое пытается компактно решить все крайние случаи, упомянутые выше:
Сокращенный результат теста (полные тестовые примеры прилагаются ниже):
Показать фрагмент кода
источник
return (func+'') .replace(/[/][/].*$/mg,'') // strip single-line comments (line-ending sensitive, so goes first) .replace(/\s+/g,'') // remove whitespace
func + ''
наFunction.toString.call(func)
для защиты от случая, когда функция имеет собственную реализацию .toString ()..split(/\)[\{=]/, 1)[0]
({ a, b, c })
) на все параметры внутри деструктуризации. чтобы сохранить не поврежденные объекты, измените последнее.split
на:.split(/,(?![^{]*})/g)
Решение, которое меньше подвержено ошибкам и пробелам:
источник
Многие ответы здесь используют регулярные выражения, это хорошо, но он не слишком хорошо обрабатывает новые дополнения к языку (например, функции стрелок и классы). Также следует отметить, что если вы используете какую-либо из этих функций в минимизированном коде, она пойдет 🔥. Он будет использовать любое минимизированное имя. Angular обходит это, позволяя передавать упорядоченный массив строк, который соответствует порядку аргументов при регистрации их в контейнере DI. Итак, с решением:
Это обрабатывает исходную проблему анализа и еще несколько типов функций (например, функции стрелок). Вот идея того, что он может и не может обрабатывать как есть:
В зависимости от того, что вы хотите использовать для прокси-серверов ES6 и деструктуризация, может быть вашим лучшим выбором. Например, если вы хотите использовать его для внедрения зависимостей (используя имена параметров), вы можете сделать это следующим образом:
Это не самый продвинутый распознаватель, но он дает представление о том, как вы можете использовать прокси для его обработки, если вы хотите использовать анализатор аргументов для простого DI. Однако в этом подходе есть одна небольшая оговорка. Нам нужно использовать деструктурирующие назначения вместо обычных параметров. Когда мы передаем прокси инжектора, деструктурирование аналогично вызову геттера объекта.
Это выводит следующее:
Его подключили все приложение. Самое приятное, что приложение легко тестировать (вы можете просто создать экземпляр каждого класса и передать его в mocks / stubs / etc). Также, если вам нужно поменять местами реализации, вы можете сделать это из одного места. Все это возможно благодаря объектам JS Proxy.
Примечание: для этого нужно проделать большую работу, прежде чем он будет готов к использованию, но он дает представление о том, как он будет выглядеть.
Это немного поздно в ответе, но это может помочь другим, кто думает о том же. 👍
источник
Я знаю, что это старый вопрос, но новички копировали его так, как будто это было хорошей практикой в любом коде. В большинстве случаев необходимость разбора строкового представления функции для использования имен ее параметров просто скрывает недостаток в логике кода.
Параметры функции на самом деле хранятся в похожем на массив объекте, который называется
arguments
, где первый аргументarguments[0]
, второй -arguments[1]
и так далее. Запись имен параметров в скобках можно рассматривать как сокращенный синтаксис. Это:...такой же как:
Сами переменные хранятся в области действия функции, а не как свойства объекта. Невозможно извлечь имя параметра через код, поскольку это просто символ, представляющий переменную на человеческом языке.
Я всегда рассматривал строковое представление функции как инструмент для целей отладки, особенно из-за этого
arguments
объекта, похожего на массив. Вы не обязаны давать имена аргументам в первую очередь. Если вы попытаетесь проанализировать строковую функцию, она не скажет вам о дополнительных безымянных параметрах, которые она может принять.Вот еще хуже и более распространенная ситуация. Если функция имеет более 3 или 4 аргументов, может быть логичным передать ей объект, с которым легче работать.
В этом случае сама функция сможет прочитать полученный объект, найти его свойства и получить их имена и значения, но попытка разобрать строковое представление функции даст только «obj» для параметров, что не полезно вообще.
источник
Function.prototype.toString = function () { return 'function () { [native code] }'; };
Proxy
( конструктор trap и apply trap ) иReflection
для обработки DI для некоторых из моих модулей. Это достаточно твердо.Поскольку JavaScript является языком сценариев, я считаю, что его самоанализ должен поддерживать получение имен параметров функций. Использование этой функциональности является нарушением первых принципов, поэтому я решил изучить эту проблему подробнее.
Это привело меня к этому вопросу, но никаких встроенных решений. Это привело меня к этому ответу, который объясняет, что
arguments
он устарел только вне функции, поэтому мы больше не можем использоватьmyFunction.arguments
или получаем:Время закатать рукава и приступить к работе:
Function Для извлечения параметров функции требуется синтаксический анализатор, поскольку сложные выражения наподобие
4*(5/3)
могут использоваться в качестве значений по умолчанию. Таким образом , ответ Гаафара или ответ Джеймса Дрю являются наилучшими подходами.Я попробовал парсеры babylon и esprima, но, к сожалению, они не могут разобрать автономные анонимные функции, как указано в ответе Матеуша Чаритонюка . Я нашел другой обходной путь, заключив код в круглые скобки, чтобы не менять логику:
Новые строки предотвращают проблемы с
//
(однострочные комментарии).⭐ Если синтаксический анализатор недоступен, следующий лучший вариант - использовать проверенный метод, такой как регулярные выражения инжектора зависимостей Angular.js. Я объединил функциональную версию ответа Lambder в с ответом humbletim игровых и добавил дополнительную
ARROW
булев для управления ли функции ES6 жира стрелки разрешены регулярными выражениями.Вот два решения, которые я собрал. Обратите внимание, что они не имеют логики для определения допустимости синтаксиса функции, они только извлекают аргументы. Обычно это нормально, так как мы обычно передаем анализируемые функции,
getArguments()
поэтому их синтаксис уже действителен.Я постараюсь курировать эти решения как можно лучше, но без усилий со стороны сопровождающих JavaScript это останется открытой проблемой.
Версия Node.js (не запускается, пока StackOverflow не поддерживает Node.js):
Полный рабочий пример:
https://repl.it/repls/SandybrownPhonyAngles
Версия браузера (обратите внимание, что он останавливается на первом комплексном значении по умолчанию):
Полный рабочий пример:
https://repl.it/repls/StupendousShowyOffices
источник
Я прочитал большинство ответов здесь, и я хотел бы добавить свою однострочную.
или
или для однострочной функции в ECMA6
__
Допустим, у вас есть функция
Код ниже вернется
"abc,def,ghi,jkl"
Этот код также будет работать с настройкой функции, которую дал Камило Мартин :
Также с комментарием Буберссона к ответу Джека Аллана :
__
объяснение
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
Это создает регулярное выражение с
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
. Я должен использовать,new RegExp
потому что я внедряю переменную (Function.name
имя целевой функции) в RegExp.Пример Если имя функции "foo" (
function foo()
), RegExp будет/foo\s*\((.*?)\)/
.Function.toString().replace(/\n/g, '')
Затем он преобразует всю функцию в строку и удаляет все символы новой строки. Удаление новых строк помогает в настройке функции, которую дал Камило Мартин .
.exec(...)[1]
Это
RegExp.prototype.exec
функция. Это в основном соответствует обычному экспоненту (new RegExp()
) в строку (Function.toString()
). Затем[1]
будет возвращена первая группа захвата, найденная в обычном экспоненте ((.*?)
)..replace(/\/\*.*?\*\//g, '').replace(/ /g, '')
Это удалит каждый комментарий внутри
/*
и*/
, и удалит все пробелы.Это также теперь поддерживает чтение и понимание
=>
функций arrow ( ), таких какf = (a, b) => void 0;
, которыеFunction.toString()
возвращали бы(a, b) => void 0
вместо нормальных функцийfunction f(a, b) { return void 0; }
. Исходное регулярное выражение вызвало бы ошибку в его путанице, но теперь оно учитывается.Изменение было от
new RegExp(Function.name+'\\s*\\((.*?)\\)')
(/Function\s*\((.*?)\)/
) доnew RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)')
(/(?:Function\s*|^)\((.*?)\)/
)Если вы хотите превратить все параметры в массив вместо строки, разделенной запятыми, в конце просто добавьте
.split(',')
.источник
f = (a, b) => void 0
; наgetParameters(f)
яTypeError: Cannot read property '1' of null
getParameters(a => b => c => d => a*b*c*d)
, которые с кодом все еще дает , чтоTypeError: Cannot read property '1' of null
... в то время как это работает stackoverflow.com/a/29123804=> ["a", "b", "c"]
источник
Вы также можете использовать парсер "esprima", чтобы избежать многих проблем с комментариями, пробелами и другими вещами в списке параметров.
Это работает даже с таким кодом:
источник
Я пытался сделать это раньше, но никогда не находил практичный способ сделать это. В итоге я вместо этого передал объект, а затем прошел через него.
источник
Я не знаю, подходит ли это решение к вашей проблеме, но оно позволяет вам переопределить любую функцию, которую вы хотите, без необходимости изменять код, который ее использует. Существующие вызовы будут использовать позиционированные параметры, в то время как реализация функции может использовать «именованные параметры» (один хэш-параметр).
Я думал, что вы в любом случае измените существующие определения функций так, почему бы не иметь заводскую функцию, которая делает именно то, что вы хотите:
Надеюсь, поможет.
источник
Правильный способ сделать это - использовать анализатор JS. Вот пример использования желудя .
Код здесь находит имена трех (формальных) параметров функции
f
. Это делается путем подачиf
вacorn.parse()
.источник
Я не знаю, как получить список параметров, но вы можете сделать это, чтобы получить, сколько он ожидает.
источник
function gotcha (a, b = false, c) {}; alert(gotcha.length)
Получив ответ от @ jack-allan, я немного изменил функцию, чтобы включить свойства ES6 по умолчанию, такие как:
чтобы все еще вернуться
[ 'a', 'b' ]
источник
Как я обычно это делаю:
Вы можете даже ссылаться на аргументы по имени функции, например:
Надеюсь это поможет!
источник
var args = name.arguments; console.log('I WANNa SEE', args);
вывести что-то вроде "{arg1: {...}, arg2: 'string'}"? Это может прояснить ситуацию(function fn (arg, argg, arrrrgggg) { console.log('#fn:', fn.arguments, Object.keys(fn.arguments)); }); fn('Huh...?', 'Wha...?', 'Magic...?');
. Аргументы функции - это объект, похожий на «массив», имеющий перечисляемые индексы. Я не думаю, что хеш-отображение возможно, но вы можете просто передать Object-литерал, что является хорошей практикой, если у вас в любом случае более 4 параметров.источник
Ответ на это требует 3 шага:
argValues
). Это просто, так как будет доступно какarguments
внутри функции.argNames
). Это не так просто и требует анализа функции. Вместо того, чтобы выполнять сложное регулярное выражение самостоятельно и беспокоиться о крайних случаях (параметры по умолчанию, комментарии, ...), вы можете использовать библиотеку наподобие babylon, которая будет анализировать функцию в абстрактном синтаксическом дереве, из которого вы можете получить имена параметров.Код будет таким
и зарегистрированный объект будет
И вот рабочий пример https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a
источник
источник
Ух ты так много ответов ... Я почти уверен, что это похоронят. Тем не менее, я подумал, что это может быть полезно для некоторых.
Я не был полностью удовлетворен выбранными ответами, поскольку в ES6 он не работает со значениями по умолчанию. И это также не предоставляет информацию о значении по умолчанию. Я также хотел облегченную функцию, которая не зависит от внешней библиотеки.
Эта функция очень полезна для целей отладки, например: регистрация вызываемой функции с ее параметрами, значениями параметров по умолчанию и аргументами.
Я потратил некоторое время на это вчера, взламывая правильный RegExp для решения этой проблемы, и это то, что я придумал. Это работает очень хорошо, и я очень доволен результатом:
Как вы можете сказать, некоторые из имен параметров исчезают, потому что конвейер Babel удаляет их из функции. Если вы запустите это в последнем NodeJS, он будет работать как положено (закомментированные результаты получены от NodeJS).
Другое замечание, как указано в комментарии, заключается в том, что он не работает с встроенными функциями стрелок в качестве значения по умолчанию. Это просто усложняет извлечение значений с помощью RegExp.
Пожалуйста, дайте мне знать, если это было полезно для вас! Хотелось бы услышать некоторые отзывы!
источник
Я приведу вам короткий пример ниже:
источник
Этот пакет использует recast для создания AST, а затем из них собираются имена параметров, что позволяет ему поддерживать сопоставление с образцом, аргументы по умолчанию, функции стрелок и другие функции ES6.
https://www.npmjs.com/package/es-arguments
источник
Я изменил версию, взятую из AngularJS, которая реализует механизм внедрения зависимостей для работы без Angular. Я также обновил
STRIP_COMMENTS
регулярное выражение для работы с нимECMA6
, поэтому он поддерживает такие вещи, как значения по умолчанию в подписи.источник
Вы можете получить доступ к значениям аргумента, переданным функции, используя свойство arguments.
источник
arguments
свойству экземпляра функции устарел. См developer.mozilla.org/en/Core_JavaScript_1.5_Reference/...Это довольно легко.
На первом месте устарела
arguments.callee
ссылка на вызываемую функцию. Во-вторых, если у вас есть ссылка на вашу функцию, вы можете легко получить их текстовое представление. В-третьих, если вы вызываете свою функцию в качестве конструктора, вы также можете иметь ссылку через yourObject.constructor. NB: Первое решение устарело, поэтому, если вы не можете его не использовать, вы должны также подумать об архитектуре вашего приложения. Если вам не нужны точные имена переменных, просто используйте внутреннюю переменную функцииarguments
без какой-либо магии.https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee
Все они собираются вызвать toString и заменить на re, чтобы мы могли создать помощника:
Некоторые примеры:
Наслаждайтесь с JS!
UPD: Джеку Аллану было предоставлено немного лучшее решение. GJ Джек!
источник
SomeFuncName
вместоarguments.callee
(оба указывают на сам объект функции).Каким бы ни было решение, оно не должно нарушать странные функции, чьи
toString()
взгляды такие же странные:Кроме того, зачем использовать сложные регулярные выражения? Это можно сделать так:
Это работает везде с каждой функцией, и единственным регулярным выражением является удаление пробелов, которое даже не обрабатывает всю строку из-за
.split
хитрости.источник
Итак, старый вопрос с множеством адекватных ответов. Вот мое предложение, которое не использует регулярные выражения, за исключением простой задачи по удалению пробелов. (Должен заметить, что функция "strips_comments" фактически удаляет их, а не удаляет физически. Это потому, что я использую его в другом месте и по разным причинам нуждаюсь в расположении оригинальных токенов без комментариев, чтобы они оставались нетронутыми)
Это довольно длинный блок кода, так как это вставка включает мини-тестовую среду.
источник
Вот один из способов:
Примечание: это работает только в браузерах, которые поддерживают
arguments.callee
.источник
Примечание: если вы хотите использовать деструктуризацию параметров ES6 в верхнем решении, добавьте следующую строку.
источник
Параметр функции строковое значение изображения динамически из JSON . Поскольку item.product_image2 является строкой URL, вам нужно поместить ее в кавычки, когда вы вызываете changeImage внутри параметра.
Моя функция Onclick
Моя функция
источник