Възможно ли е да се отразят аргументите на функция на Javascript?

Възможно ли е да получите всички аргументи, които функцията на Javascript е написана да приема? (Знам, че всички аргументи на функцията на Javascript са „незадължителни“)? Ако не, възможно ли е да получите броя на аргументите? Например в PHP може да се използва:

$class = new ReflectionClass('classNameHere');
$methods = $class->getMethods();
foreach ($methods as $method) {
    print_r($method->getParameters());
}

... или нещо подобно, не съм докосвал PHP от известно време, така че примерът по-горе може да не е правилен.

Благодаря предварително!

РЕДАКТИРАНЕ: За съжаление, трябва да мога да получа аргументите извън тялото на функцията... Съжалявам за липсата на пояснение, но благодаря за текущите отговори!


person Jonathan Chan    schedule 03.08.2011    source източник
comment
отстраняването на грешки с getParameters() просто ме вбесява. искам да кажа, че това не е полезно, просто казвам, че това е всичко. може би има по-добър начин за решаване на проблема ви.   -  person Winfield Trail    schedule 03.08.2011
comment
Със сигурност има. Чрез ключовата дума arguments (вътре във функция това е обект, подобен на масив, където arguments[0] е първият аргумент и т.н.). Това не е отговор, защото съм твърде мързелив, за да намеря добра справка. Това обаче излага само стойностите, не и имената. В зависимост от конкретна реализация на To String за функция, имената могат да бъдат извлечени чрез това и магия за анализиране.   -  person    schedule 03.08.2011
comment
@sudowned :/ Не отстранявам грешки, отражението е неразделна част от дизайна на моето приложение...   -  person Jonathan Chan    schedule 03.08.2011
comment
@pst За съжаление трябва да мога да получа аргументите извън тялото на функцията - актуализирам въпроса.   -  person Jonathan Chan    schedule 03.08.2011
comment
Доста късно, но явно терминът, който търсех, бяха параметри. Открих (доста сложен) начин да ги получа: jsbin.com/ucacit.   -  person Jonathan Chan    schedule 03.01.2012


Отговори (7)


Да предположим, че името на вашата функция е foo

Възможно ли е да получите всички аргументи, които една функция на Javascript е написана да приема?

arguments[0] to arguments[foo.length-1]

Ако не, възможно ли е да получите броя на аргументите?

foo.length ще работи

person wong2    schedule 03.08.2011
comment
Мисля, че свойството .length е най-доброто, което можете да направите. В крайна сметка, на кого му пука какви са имената на параметрите? - person Ray Toal; 03.08.2011
comment
Съжалявам за лошата формулировка, но това възнамерявах да направя. Благодаря! :) - person Jonathan Chan; 03.08.2011

Тази нова версия обработва и функциите на дебелите стрелки...

args = f => f.toString ().replace (/[\r\n\s]+/g, ' ').
              match (/(?:function\s*\w*)?\s*(?:\((.*?)\)|([^\s]+))/).
              slice (1,3).
              join ('').
              split (/\s*,\s*/);

function ftest (a,
                 b,
                 c) { }

let aftest = (a,
                 b,
                 c) => a + b / c;

console.log ( args (ftest),  // = ["a", "b", "c"] 
              args (aftest), // = ["a", "b", "c"]
              args (args)    // = ["f"]
             );

Ето какво мисля, че търсите:

 function ftest (a,
                 b,
                 c) { }
 var args = ftest.toString ().
              replace (/[\r\n\s]+/g, ' ').
              match (/function\s*\w*\s*\((.*?)\)/)[1].split (/\s*,\s*/);

args ще бъде масив от имената на аргументите на теста, т.е. ['a', 'b', 'c']

Стойността е args ще бъде масив от имена на параметри, ако ftest е функция. Масивът ще бъде празен, ако ftest няма параметри. Стойността на args ще бъде null, ако ftest не успее да съвпадне с регулярен израз, т.е. не е функция.

person HBP    schedule 03.08.2011
comment
Един малък недостатък във вашия регулярен израз, че Angular в адреса на отговора на @Etienne е първият \s+, ще предотврати съвпадение на анонимни функции без интервал между ключовата дума и скобите, т.е. function(x,y) { /* ... */ }. Това може да се избегне, като вместо това се промени на \s*. - person GregL; 26.06.2013
comment
Благодаря за това, в моето собствено кодиране винаги поставям това място. Актуализирах кода. - person HBP; 26.06.2013
comment
Грешката, която GregL посочи в първия ви пример, също се появява (в малко по-различна форма) във вашия втори. Регулярният израз вероятно трябва да гласи /^\s*function(?:\s+\w*)?\s*\(([\s\S]*?)\)/. (Също така го направих така, че да позволява многоредови списъци с аргументи.) - person Brian McCutchon; 15.07.2013
comment
Благодаря за доклада. Function.toString не връща източника, както сте го въвели (поне в браузърите, които съм тествал). но връща преформатирана версия, така че някои от тези промени може да не са строго погледнато необходими. За да го направите абсолютно безупречен, ще трябва да се погрижите за коментарите, където интервалът е валиден. - person HBP; 15.07.2013
comment
Защо усложнявате регулярния израз толкова много? Защо просто не направите това: ftest.toString().match(/\([^\)]*\)/m)[0].match(/[^\n\r\s,\)\(]/g). По същество се съпоставя всичко между първата двойка кръгли скоби (т.е. (<content>)) и след това се съпоставя всичко, което не е скоба, запетая или интервал в тези скоби. - person Nadeem Douba; 09.07.2015
comment
@nadeem Re коментара ми от 15 юли '13 по-горе. Стойността, върната от функцията toString, приложена към function, не е напълно посочена. Може да е дезинфекцирана версия или оригиналния изходен текст. Във втория случай е възможно да има коментари. Допълнителната проверка в регулярния израз намалява шансовете за грешно съвпадение в тези случаи. - person HBP; 10.07.2015
comment
Благодаря за отговора. Това обаче не работи, ако имате нов ред в подписа си. Решението от @Etienne прави stackoverflow.com/a/13660631/653799 - person Juan Campa; 07.08.2016
comment
@HBP какво ще кажете за функции със стрелки? - person Kiril; 16.05.2017

възможно е да получите цялото официално име на параметър на javascript:

var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

function formalParameterList(fn) {
   var fnText,argDecl;
   var args=[];
   fnText = fn.toString().replace(STRIP_COMMENTS, '');
   argDecl = fnText.match(FN_ARGS); 

   var r = argDecl[1].split(FN_ARG_SPLIT);
   for(var a in r){
      var arg = r[a];
      arg.replace(FN_ARG, function(all, underscore, name){
         args.push(name);
      });
   }
   return args;
 }

това може да се тества по следния начин:

 var expect = require('expect.js');
 expect( formalParameterList(function() {} )).to.eql([]);
 expect( formalParameterList(function () {} )).to.eql([]);
 expect( formalParameterList(function /*  */ () {} )).to.eql([]);
 expect( formalParameterList(function (/* */) {} )).to.eql([]);
 expect( formalParameterList(function ( a,   b, c  ,d /* */, e) {} )).to.eql(['a','b','c','d','e']);

Забележка: Тази техника се използва с $injector на AngularJs и е внедрена във функцията за анотиране. (вижте https://github.com/angular/angular.js/blob/master/src/auto/injector.js и съответния модулен тест в https://github.com/angular/angular.js/blob/master/auto/injectorSpec.js )

person Etienne    schedule 01.12.2012
comment
Каква е целта на улавянето на подчертаването на параметъра отделно и игнорирането му? - person Carl G; 15.06.2013
comment
Страхотно решение. Не разбирам защо, ако взема функции от this, не мога да приложа към него, вижте getAllFunctions от @kooinc в stackoverflow.com/questions/11279441/ и коментара по-долу. - person loretoparisi; 16.03.2016

проверете само необходимите знаци. с func.toString().regex сте проверили пълната дължина. Така че, ако функцията е клас с 500 реда код...

function getParams(func){
    var str=func.toString();
    var len = str.indexOf("(");
    return str.substr(len+1,str.indexOf(")")-len -1).replace(/ /g,"").split(',')
}
person Tito100    schedule 24.09.2013

Сега, когато казвате извън тялото на функцията мога само да си представя, че искате да знаете какви са имената на параметрите? Защото що се отнася до стойностите, вие вече знаете какви аргументи подавате. Други отговори казаха, че можете да получите дължината на функцията, което е броят на параметрите, които тя изрично декларира. Сега, ако искате да знаете имената извън функцията, какво ще кажете за хака toString?

Обмисли

function f(oh, hi, there) {
    return hi + there / oh;
}

Тогава

alert(f);

Какво виждаш? Точно така, просто ги изведете с регекс! Добре, ИЗВИНЕТЕ, че повдигнах това. Може би не е стандартен ECMAScript, но работи в Chrome....

person Ray Toal    schedule 03.08.2011

Отговорът на HBP е това, което повечето хора търсят, но ако вие сте този, който дефинира функцията, можете също да присвоите свойство на функционалния обект. Например,

a.arguments = ['foo', 'bar', 'baz']
function a(foo, bar, baz) {
  // do stuff
}

Това вероятно е по-ясно, но ще трябва да напишете аргументите си два пъти.

person nucleartide    schedule 02.06.2016

JavaScript е диалект на ECMAScript, според стандарта ECMAScript, функцията също е обект и когато се извика функция, функцията може да има достъп до обект аргументи, този аргумент е подобен на масив обект, има свойство дължина, така че можете да използвате аргументи .length за преминаване на всички аргументи, предадени на тази функция. посетете http://interglacial.com/javascript_spec/a-13.html#a-13.2.1 за повече подробности.

person xudifsd    schedule 03.08.2011