Динамическое получение имён и значений параметров в функции
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
Извлечение имен параметров и их значений в JavaScript теперь возможно с элегантной простотой:
const getParams = (func) => {
const names = func.toString().match(/(?<=\().*?(?=\))/)[0].split(',').map(name => name.trim());
return (args) => names.reduce((obj, name, index) => (obj[name] = args[index], obj), {});
};
// Практический пример:
function foo(x, y, z) {
const params = getParams(foo)(arguments);
console.log(params); // Вывод: { x: 1, y: 2, z: 3 }
}
foo(1, 2, 3);
Этот элегантный метод использует .match()
для извлечения параметров из определения функции. Далее с помощью .split
и .trim()
, он преобразует их в массив имен. С использованием .reduce()
свойства и их значения связываются вместе, трансформируя параметры в объект.
Обработка параметров по умолчанию и исключений
Действительность зачастую сложнее, что в полной мере относится и к параметрам функции. В ES6 были введены параметры по умолчанию, которые могут усложнить задачу. Но нет ничего невозможного:
const getParamsDefault = (func) => {
const functionString = func.toString();
const names = functionString.slice(functionString.indexOf('(') + 1, functionString.indexOf(')'))
.replace(/\/\*.*?\*\/|\/\/.*(?=\n)/g, '')
.split(',')
.map(name => name.replace(/=[^,]+/, '').trim());
return (args) => Array.from(args).reduce((obj, value, index) => {
obj[names[index]] = value;
return obj;
}, {});
};
// Пример использования:
function bar(x, y = 2, z = 3) {
const params = getParamsDefault(bar)(arguments);
console.log(params); // Вывод: { x: 1, y: 2, z: 3 }
}
bar(1);
Усовершенствованное регулярное выражение исключает комментарии и значения по умолчанию, позволяя более точно определить имена параметров. Преобразование arguments
в массив с помощью Array.from()
обеспечивает точное соответствие между именами и значениями параметров.
Использование внешних библиотек для работы с сложностями
Нередко специфические форматы функций или минимизированный код вынуждают нас отказываться от собственных решений в пользу более продвинутых инструментов, таких как AST-парсеры, например, Esprima:
const esprima = require('esprima');
const getParamsAdvanced = (func) => {
const ast = esprima.parseScript(func.toString());
const params = ast.body[0].params.map(param => param.name);
return (args) => Array.from(args).reduce((obj, value, index) => (obj[params[index]] = value, obj), {});
};
// Пример использования:
const complexFunction = (a, b) => { /* Сложная и недооцененная */ };
const params = getParamsAdvanced(complexFunction)(['value1', 'value2']);
console.log(params); // Вывод: { a: 'value1', b: 'value2' }
В сложных случаях на помощь приходит Esprima, преобразуя функцию в абстрактное синтаксическое дерево (AST) и обеспечивая доступ к именам параметров, не обращая внимания на пробелы, комментарии или сокращенную запись кода.
Визуализация
Cчитайте функцию списком ингредиентов для рецепта 🍲. Параметры – это ваши ингредиенты:
function bakeCake(flour, sugar, eggs) { ... }
Мы подготавливаем ингредиенты (параметры) до начала процесса приготовления:
Список ингредиентов: [🌾 мука, 🍚 сахар, 🥚 яйца]
Определение наименования и измерение величины:
Ингредиенты: ['мука', 'сахар', 'яйца'] // Названия параметров
Количества: [300, 200, 3] // Значения параметров
Всё готово, и вы уже способны представить будущее блюдо, взглянув на список ингредиентов.
| Ингредиент | Количество |
| -----------| ---------- |
| 🌾 мука | 300г |
| 🍚 сахар | 200г |
| 🥚 яйца | 3 шт. |
🍲 Осталось только надеть шеф-поварскую шапку и приступить к приготовлению!
Специфика работы с динамическими функциями
Адаптация к различным условиям использования функций требует индивидуального подхода. Будьте особенно осторожны при работе со стрелочными функциями, методами и функциями с синтаксисом остаточных параметров:
В стрелочных функциях нет места для
arguments
. Вместо этого используйте именованные параметры или...rest
.Методы объектов и классов имеют свой контекст (
this
). Не нарушайте его при работе с параметрами.Остаточные параметры (
...args
) могут включать все аргументы функции. Учитывайте это при анализе исходного кода функции.
Производительность и лучшие практики
При решении задач, связанных с производительностью, анализ функций видится как лишняя нагрузка. Он замедляет работу и может ввести в заблуждение оптимизирующие алгоритмы JavaScript-движков.
Кроме того, использование регулярных выражений или анализа AST может вызвать заблуждения из-за того, что сторонний код может отличаться от вашего стиля программирования.
В AngularJS практически всегда предпочтительнее использовать существующее внедрение зависимости, например, $inject
, чем создавать функцию с нуля.
Полезные материалы
- Функции – JavaScript | MDN – ваш надежный гид по параметрам функций в JavaScript.
- Reflect – JavaScript | MDN – исследуйте мир метапрограммирования и тонкости работы с Reflect API.
- Понимание вызова функции в JavaScript и "this" – углубленное объяснение механизмов вызова функций и контекста
this
. - Функции высшего порядка :: Eloquent JavaScript – научитесь адаптировать функции под свои конкретные потребности.
- Объект arguments – JavaScript | MDN – подробное изучение работы с параметрами функций через объект
arguments
.