w3schools valor utiliza una tipos terminar retornar pasar parametros para lista las instrucciones funciones funcion ejemplos desde javascript reflection function-parameter

javascript - utiliza - ¿Cómo obtener dinámicamente nombres/valores de parámetros de función?



retornar valor de una funcion javascript (30)

A continuación se muestra el código tomado de AngularJS, que utiliza la técnica para su mecanismo de inyección de dependencia.

Y aquí hay una explicación de esto tomada de http://docs.angularjs.org/tutorial/step_05

El inyector de dependencia de Angular proporciona servicios a su controlador cuando se está construyendo el controlador. El inyector de dependencia también se encarga de crear cualquier dependencia transitiva que pueda tener el servicio (los servicios a menudo dependen de otros servicios).

Tenga en cuenta que los nombres de los argumentos son significativos, porque el inyector los utiliza para buscar las dependencias.

/** * @ngdoc overview * @name AUTO * @description * * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}. */ var FN_ARGS = /^function/s*[^/(]*/(/s*([^/)]*)/)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^/s*(_?)(.+?)/1/s*$/; var STRIP_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; function annotate(fn) { var $inject, fnText, argDecl, last; if (typeof fn == ''function'') { if (!($inject = fn.$inject)) { $inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''''); argDecl = fnText.match(FN_ARGS); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); fn.$inject = $inject; } } else if (isArray(fn)) { last = fn.length - 1; assertArgFn(fn[last], ''fn'') $inject = fn.slice(0, last); } else { assertArgFn(fn, ''fn'', true); } return $inject; }

¿Hay una manera de obtener los nombres de parámetros de función de una función dinámicamente?

Digamos que mi función se ve así:

function doSomething(param1, param2, .... paramN){ // fill an array with the parameter name and value // some other code }

Ahora, ¿cómo obtendría una lista de los nombres de los parámetros y sus valores en una matriz desde dentro de la función?


Aquí hay una solución actualizada que intenta abordar todos los casos de borde mencionados anteriormente de una manera compacta:

function $args(func) { return (func + '''') .replace(/[/][/].*$/mg,'''') // strip single-line comments .replace(//s+/g, '''') // strip white space .replace(/[/][*][^/*]*[*][/]/g, '''') // strip multi-line comments .split(''){'', 1)[0].replace(/^[^(]*[(]/, '''') // extract the parameters .replace(/=[^,]+/g, '''') // strip any ES6 defaults .split('','').filter(Boolean); // split & filter [""] }

Salida de prueba abreviada (los casos de prueba completos se adjuntan a continuación):

''function (a,b,c)...'' // returns ["a","b","c"] ''function ()...'' // returns [] ''function named(a, b, c) ...'' // returns ["a","b","c"] ''function (a /* = 1 */, b /* = true */) ...'' // returns ["a","b"] ''function fprintf(handle, fmt /*, ...*/) ...'' // returns ["handle","fmt"] ''function( a, b = 1, c )...'' // returns ["a","b","c"] ''function (a=4*(5/3), b) ...'' // returns ["a","b"] ''function (a, // single-line comment xjunk) ...'' // returns ["a","b"] ''function (a /* fooled you...'' // returns ["a","b"] ''function (a /* function() yes */, /n /* no, */b)/* omg! */...'' // returns ["a","b"] ''function ( A, b /n,c ,d /n ) /n ...'' // returns ["A","b","c","d"] ''function (a,b)...'' // returns ["a","b"] ''function $args(func) ...'' // returns ["func"] ''null...'' // returns ["null"] ''function Object() ...'' // returns []

function $args(func) { return (func + '''') .replace(/[/][/].*$/mg,'''') // strip single-line comments .replace(//s+/g, '''') // strip white space .replace(/[/][*][^/*]*[*][/]/g, '''') // strip multi-line comments .split(''){'', 1)[0].replace(/^[^(]*[(]/, '''') // extract the parameters .replace(/=[^,]+/g, '''') // strip any ES6 defaults .split('','').filter(Boolean); // split & filter [""] } // test cases document.getElementById(''console_info'').innerHTML = ( [ // formatting -- typical function(a,b,c){}, function(){}, function named(a, b, c) { /* multiline body */ }, // default values -- conventional function(a /* = 1 */, b /* = true */) { a = a||1; b=b||true; }, function fprintf(handle, fmt /*, ...*/) { }, // default values -- ES6 "function( a, b = 1, c ){}", "function (a=4*(5/3), b) {}", // embedded comments -- sardonic function(a, // single-line comment xjunk) {} b //,c,d ) // single-line comment {}, function(a /* fooled you{*/,b){}, function /* are you kidding me? (){} */(a /* function() yes */, /* no, */b)/* omg! */{/*}}*/}, // formatting -- sardonic function ( A, b ,c ,d ) { }, // by reference this.jQuery || function (a,b){return new e.fn.init(a,b,h)}, $args, // inadvertent non-function values null, Object ].map(function(f) { var abbr = (f + '''').replace(//n/g, ''//n'').replace(//s+|[{]+$/g, '' '').split("{", 1)[0] + "..."; return " ''" + abbr + "'' // returns " + JSON.stringify($args(f)); }).join("/n") + "/n"); // output for copy and paste as a markdown snippet

<pre id=''console_info''></pre>


Dado que JavaScript es un lenguaje de scripting, creo que su introspección debería permitir obtener nombres de parámetros de función. Punting en esa funcionalidad es una violación de los primeros principios, por lo que decidí explorar el tema más a fondo.

Eso me llevó a esta pregunta, pero no a soluciones integradas. Lo que me llevó a esta respuesta que explica que los arguments solo están en desuso fuera de la función, por lo que ya no podemos usar myFunction.arguments o obtenemos:

//define like function test(args) { for(var item in args) { alert(item); alert(args[item]); } } //then used like test({ name:"Joe", age:40, admin:bool });

Es hora de arremangarnos y ponernos a trabajar:

⭐ La recuperación de los parámetros de la función requiere un analizador porque las expresiones complejas como 4*(5/3) se pueden usar como valores predeterminados. Así que la respuesta de Gaafar o la respuesta de James Drew son hasta ahora los mejores enfoques.

esprima analizadores de esprima y esprima pero desafortunadamente no pueden analizar funciones anónimas independientes, como se señaló en la respuesta de Mateusz Charytoniuk . Sin embargo, descubrí otra solución al encerrar el código entre paréntesis, para no cambiar la lógica:

(function(a,b,c){}).toString().replace(/.*/(|/).*/ig,"").split('','')

Las nuevas líneas previenen problemas con // (comentarios de una sola línea).

⭐ Si un analizador no está disponible, la mejor opción es utilizar una técnica probada y verdadera como las expresiones regulares del inyector de dependencia de Angular.js. Combiné una versión funcional de la respuesta de Lambder con la respuesta de humbletim y agregué un booleano ARROW opcional para controlar si las expresiones regulares permiten las funciones de flecha gruesa ES6.

Aquí hay dos soluciones que puse juntas. Tenga en cuenta que estos no tienen lógica para detectar si una función tiene una sintaxis válida, solo extraen los argumentos. Esto generalmente es correcto ya que generalmente pasamos funciones analizadas a getArguments() por lo que su sintaxis ya es válida.

Intentaré curar estas soluciones lo mejor que pueda, pero sin el esfuerzo de los mantenedores de JavaScript, esto seguirá siendo un problema abierto.

Versión de Node.js (no ejecutable hasta que admita Node.js):

TypeError: ''caller'', ''callee'', and ''arguments'' properties may not be accessed on strict mode functions or the arguments objects for calls to them

Ejemplo de trabajo completo:

https://repl.it/repls/SandybrownPhonyAngles

Versión del navegador (tenga en cuenta que se detiene en el primer valor predeterminado complejo):

const ast = parser.parse("(/n" + func.toString() + "/n)")

Ejemplo de trabajo completo:

https://repl.it/repls/StupendousShowyOffices


He intentado hacer esto antes, pero nunca encontré una manera práctica de hacerlo. Terminé pasando un objeto en su lugar y luego lo hice en bucle.

const parserName = ''babylon''; // const parserName = ''esprima''; const parser = require(parserName); function getArguments(func) { const maybe = function (x) { return x || {}; // optionals support } try { const ast = parser.parse("(/n" + func.toString() + "/n)"); const program = parserName == ''babylon'' ? ast.program : ast; return program .body[0] .expression .params .map(function(node) { return node.name || maybe(node.left).name || ''...'' + maybe(node.argument).name; }); } catch (e) { return []; // could also return null } }; ////////// TESTS ////////// function logArgs(func) { let object = {}; object[func] = getArguments(func); console.log(object); // console.log(/*JSON.stringify(*/getArguments(func)/*)*/); } console.log(''''); console.log(''////////// MISC //////////''); logArgs((a, b) => {}); logArgs((a, b = 1) => {}); logArgs((a, b, ...args) => {}); logArgs(function(a, b, ...args) {}); logArgs(function(a, b = 1, c = 4 * (5 / 3), d = 2) {}); logArgs(async function(a, b, ...args) {}); logArgs(function async(a, b, ...args) {}); console.log(''''); console.log(''////////// FUNCTIONS //////////''); logArgs(function(a, b, c) {}); logArgs(function() {}); logArgs(function named(a, b, c) {}); logArgs(function(a /* = 1 */, b /* = true */) {}); logArgs(function fprintf(handle, fmt /*, ...*/) {}); logArgs(function(a, b = 1, c) {}); logArgs(function(a = 4 * (5 / 3), b) {}); // logArgs(function (a, // single-line comment xjunk) {}); // logArgs(function (a /* fooled you {}); // logArgs(function (a /* function() yes */, /n /* no, */b)/* omg! */ {}); // logArgs(function ( A, b /n,c ,d /n ) /n {}); logArgs(function(a, b) {}); logArgs(function $args(func) {}); logArgs(null); logArgs(function Object() {}); console.log(''''); console.log(''////////// STRINGS //////////''); logArgs(''function (a,b,c) {}''); logArgs(''function () {}''); logArgs(''function named(a, b, c) {}''); logArgs(''function (a /* = 1 */, b /* = true */) {}''); logArgs(''function fprintf(handle, fmt /*, ...*/) {}''); logArgs(''function( a, b = 1, c ) {}''); logArgs(''function (a=4*(5/3), b) {}''); logArgs(''function (a, // single-line comment xjunk) {}''); logArgs(''function (a /* fooled you {}''); logArgs(''function (a /* function() yes */, /n /* no, */b)/* omg! */ {}''); logArgs(''function ( A, b /n,c ,d /n ) /n {}''); logArgs(''function (a,b) {}''); logArgs(''function $args(func) {}''); logArgs(''null''); logArgs(''function Object() {}'');


He leído la mayoría de las respuestas aquí, y me gustaría agregar mi one-liner.

new RegExp(Function.name+''//s*//((.*?)//)'').exec(Function.toString().replace(//n/g, ''''))[1].replace(////*.*?/*///g, '''').replace(/ /g, '''')

o

function getParameters(func) { return new RegExp(func.name+''//s*//((.*?)//)'').exec(func.toString().replace(//n/g, ''''))[1].replace(////*.*?/*///g, '''').replace(/ /g, ''''); }

o para una función de una sola línea en ECMA6

var getParameters = func => new RegExp(func.name+''//s*//((.*?)//)'').exec(func.toString().replace(//n/g, ''''))[1].replace(////*.*?/*///g, '''').replace(/ /g, '''');

__

Digamos que tienes una función

function foo(abc, def, ghi, jkl) { //code }

El siguiente código devolverá "abc,def,ghi,jkl"

Ese código también funcionará con la configuración de una función que Camilo Martin dio:

function ( A, b ,c ,d ){}

También con el comentario de Bubersson sobre la respuesta de Jack Allan :

function(a /* fooled you)*/,b){}

__

Explicación

new RegExp(Function.name+''//s*//((.*?)//)'')

Esto crea un Exponente regular con el new RegExp(Function.name+''//s*//((.*?)//)'') . Tengo que usar el new RegExp porque estoy inyectando una variable ( Function.name , el nombre de la función que se está seleccionando) en el RegExp.

Ejemplo Si el nombre de la función es "foo" ( function foo() ), el RegExp será /foo/s*/((.*?)/)/ .

Function.toString().replace(//n/g, '''')

Luego convierte toda la función en una cadena y elimina todas las nuevas líneas. Eliminar nuevas líneas ayuda con la configuración de la función que Camilo Martin dio.

.exec(...)[1]

Esta es la RegExp.prototype.execfunción. Básicamente coincide con el Exponente Regular ( new RegExp()) en la Cadena ( Function.toString()). Luego [1]devolverá el primer grupo de captura encontrado en el exponente regular ( (.*?)).

.replace(////*.*?/*///g, '''').replace(/ /g, '''')

Esto eliminará todos los comentarios dentro /*y */, y eliminará todos los espacios.

Si desea convertir todos los parámetros en una matriz en lugar de una cadena separada por comas, al final solo agregue .split('','').


La siguiente función devolverá una matriz de los nombres de parámetros de cualquier función pasada.

var STRIP_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; var ARGUMENT_NAMES = /([^/s,]+)/g; function getParamNames(func) { var fnStr = func.toString().replace(STRIP_COMMENTS, ''''); var result = fnStr.slice(fnStr.indexOf(''('')+1, fnStr.indexOf('')'')).match(ARGUMENT_NAMES); if(result === null) result = []; return result; }

Ejemplo de uso:

getParamNames(getParamNames) // returns [''func''] getParamNames(function (a,b,c,d){}) // returns [''a'',''b'',''c'',''d''] getParamNames(function (a,/*b,c,*/d){}) // returns [''a'',''d''] getParamNames(function (){}) // returns []

Editar :

Con el invento de ES6, esta función puede ser activada por parámetros predeterminados. Aquí hay un truco rápido que debería funcionar en la mayoría de los casos:

var STRIP_COMMENTS = /(////.*$)|(///*[/s/S]*?/*//)|(/s*=[^,/)]*((''(?://'|[^''/r/n])*'')|("(?://"|[^"/r/n])*"))|(/s*=[^,/)]*))/mg;

Digo la mayoría de los casos porque hay algunas cosas que lo harán tropezar

function (a=4*(5/3), b) {} // returns [''a'']

Edición : También tengo en cuenta que vikasde también quiere los valores de los parámetros en una matriz. Esto ya se proporciona en una variable local llamada argumentos.

extracto de https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments :

El objeto de argumentos no es un Array. Es similar a una matriz, pero no tiene propiedades de matriz excepto la longitud. Por ejemplo, no tiene el método pop. Sin embargo, se puede convertir en una matriz real:

var args = Array.prototype.slice.call(arguments);

Si Array genéricos está disponible, uno puede usar lo siguiente:

var args = Array.slice(arguments);


La solución que es menos propensa a errores de espacios y comentarios sería:

var fn = function(/* whoa) */ hi, you){}; fn.toString() .replace(/((////.*$)|(///*[/s/S]*?/*//)|(/s))/mg,'''') .match(/^function/s*[^/(]*/(/s*([^/)]*)/)/m)[1] .split(/,/) ["hi", "you"]


Muchas de las respuestas aquí usan expresiones regulares, esto está bien, pero no maneja las nuevas adiciones al lenguaje demasiado bien (como las funciones de flecha y las clases). También se debe tener en cuenta que si utiliza cualquiera de estas funciones en el código minimizado, se ejecutará 🔥. Usará cualquiera que sea el nombre minificado. Angular soluciona esto al permitirle pasar una serie ordenada de cadenas que coinciden con el orden de los argumentos cuando se registran con el contenedor DI. Así que con la solución:

var esprima = require(''esprima''); var _ = require(''lodash''); const parseFunctionArguments = (func) => { // allows us to access properties that may or may not exist without throwing // TypeError: Cannot set property ''x'' of undefined const maybe = (x) => (x || {}); // handle conversion to string and then to JSON AST const functionAsString = func.toString(); const tree = esprima.parse(functionAsString); console.log(JSON.stringify(tree, null, 4)) // We need to figure out where the main params are. Stupid arrow functions 👊 const isArrowExpression = (maybe(_.first(tree.body)).type == ''ExpressionStatement''); const params = isArrowExpression ? maybe(maybe(_.first(tree.body)).expression).params : maybe(_.first(tree.body)).params; // extract out the param names from the JSON AST return _.map(params, ''name''); };

Esto maneja el problema de análisis original y algunos tipos de funciones más (por ejemplo, funciones de flecha). Aquí hay una idea de lo que puede y no puede manejar como es:

// I usually use mocha as the test runner and chai as the assertion library describe(''Extracts argument names from function signature. 💪'', () => { const test = (func) => { const expectation = [''it'', ''parses'', ''me'']; const result = parseFunctionArguments(toBeParsed); result.should.equal(expectation); } it(''Parses a function declaration.'', () => { function toBeParsed(it, parses, me){}; test(toBeParsed); }); it(''Parses a functional expression.'', () => { const toBeParsed = function(it, parses, me){}; test(toBeParsed); }); it(''Parses an arrow function'', () => { const toBeParsed = (it, parses, me) => {}; test(toBeParsed); }); // ================= cases not currently handled ======================== // It blows up on this type of messing. TBH if you do this it deserves to // fail 😋 On a tech note the params are pulled down in the function similar // to how destructuring is handled by the ast. it(''Parses complex default params'', () => { function toBeParsed(it=4*(5/3), parses, me) {} test(toBeParsed); }); // This passes back [''_ref''] as the params of the function. The _ref is a // pointer to an VariableDeclarator where the ✨🦄 happens. it(''Parses object destructuring param definitions.'' () => { function toBeParsed ({it, parses, me}){} test(toBeParsed); }); it(''Parses object destructuring param definitions.'' () => { function toBeParsed ([it, parses, me]){} test(toBeParsed); }); // Classes while similar from an end result point of view to function // declarations are handled completely differently in the JS AST. it(''Parses a class constructor when passed through'', () => { class ToBeParsed { constructor(it, parses, me) {} } test(ToBeParsed); }); });

Dependiendo de lo que quiera usar para los proxies ES6 y la desestructuración puede ser su mejor apuesta. Por ejemplo, si desea usarlo para inyección de dependencia (utilizando los nombres de los parámetros), puede hacerlo de la siguiente manera:

class GuiceJs { constructor() { this.modules = {} } resolve(name) { return this.getInjector()(this.modules[name]); } addModule(name, module) { this.modules[name] = module; } getInjector() { var container = this; return (klass) => { console.log(klass); var paramParser = new Proxy({}, { // The `get` handler is invoked whenever a get-call for // `injector.*` is made. We make a call to an external service // to actually hand back in the configured service. The proxy // allows us to bypass parsing the function params using // taditional regex or even the newer parser. get: (target, name) => container.resolve(name), // You shouldn''t be able to set values on the injector. set: (target, name, value) => { throw new Error(`Don''t try to set ${name}! 😑`); } }) return new klass(paramParser); } } }

No es el resolvedor más avanzado que existe, pero da una idea de cómo puede usar un Proxy para manejarlo si desea usar el analizador Args para DI simple. Sin embargo, hay una ligera advertencia en este enfoque. Necesitamos usar tareas de desestructuración en lugar de parámetros normales. Cuando pasamos en el proxy del inyector, la destrucción es lo mismo que llamar al captador en el objeto.

class App { constructor({tweeter, timeline}) { this.tweeter = tweeter; this.timeline = timeline; } } class HttpClient {} class TwitterApi { constructor({client}) { this.client = client; } } class Timeline { constructor({api}) { this.api = api; } } class Tweeter { constructor({api}) { this.api = api; } } // Ok so now for the business end of the injector! const di = new GuiceJs(); di.addModule(''client'', HttpClient); di.addModule(''api'', TwitterApi); di.addModule(''tweeter'', Tweeter); di.addModule(''timeline'', Timeline); di.addModule(''app'', App); var app = di.resolve(''app''); console.log(JSON.stringify(app, null, 4));

Esto da como resultado lo siguiente:

{ "tweeter": { "api": { "client": {} } }, "timeline": { "api": { "client": {} } } }

Está cableado toda la aplicación. Lo mejor es que la aplicación es fácil de probar (puedes crear una instancia de cada clase y pasar mocks / stubs / etc). Además, si necesita intercambiar implementaciones, puede hacerlo desde un solo lugar. Todo esto es posible gracias a los objetos JS Proxy.

Nota: Es necesario hacer mucho trabajo antes de que esté listo para el uso de producción, pero da una idea de cómo se vería.

Es un poco tarde en la respuesta, pero puede ayudar a otros que están pensando lo mismo. 👍


No sé si esta solución se adapta a su problema, pero le permite redefinir cualquier función que desee, sin tener que cambiar el código que la usa. Las llamadas existentes usarán parámetros posicionados, mientras que la implementación de la función puede usar "parámetros denominados" (un único parámetro hash).

Pensé que, de todos modos, modificaría las definiciones de funciones existentes, así que, ¿por qué no tener una función de fábrica que haga lo que usted desea:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> var withNamedParams = function(params, lambda) { return function() { var named = {}; var max = arguments.length; for (var i=0; i<max; i++) { named[params[i]] = arguments[i]; } return lambda(named); }; }; var foo = withNamedParams(["a", "b", "c"], function(params) { for (var param in params) { alert(param + ": " + params[param]); } }); foo(1, 2, 3); </script> </head> <body> </body> </html>

Espero eso ayude.


También puede usar el analizador "esprima" para evitar muchos problemas con los comentarios, espacios en blanco y otras cosas dentro de la lista de parámetros.

function getParameters(yourFunction) { var i, // safetyValve is necessary, because sole "function () {...}" // is not a valid syntax parsed = esprima.parse("safetyValve = " + yourFunction.toString()), params = parsed.body[0].expression.right.params, ret = []; for (i = 0; i < params.length; i += 1) { // Handle default params. Exe: function defaults(a = 0,b = 2,c = 3){} if (params[i].type == ''AssignmentPattern'') { ret.push(params[i].left.name) } else { ret.push(params[i].name); } } return ret; }

Funciona incluso con código como este:

getParameters(function (hello /*, foo ),* /bar* { */,world) {}); // ["hello", "world"]


Sé que esta es una pregunta antigua, pero los principiantes han copiado esta prueba como si fuera una buena práctica en cualquier código. La mayoría de las veces, tener que analizar una representación de cadena de una función para usar los nombres de sus parámetros simplemente oculta una falla en la lógica del código.

Los parámetros de una función en realidad se almacenan en un objeto similar a una matriz llamado arguments , donde el primer argumento es arguments[0] , el segundo es arguments[1] y así sucesivamente. Escribir nombres de parámetros en los paréntesis puede verse como una sintaxis abreviada. Esta:

function doSomething(foo, bar) { console.log("does something"); }

...es lo mismo que:

function doSomething() { var foo = arguments[0]; var bar = arguments[1]; console.log("does something"); }

Las variables en sí se almacenan en el alcance de la función, no como propiedades en un objeto. No hay manera de recuperar el nombre del parámetro a través del código, ya que es simplemente un símbolo que representa la variable en lenguaje humano.

Siempre consideré la representación de cadena de una función como una herramienta para propósitos de depuración, especialmente debido a este arguments de tipo objeto de matriz. No es necesario que dé nombres a los argumentos en primer lugar. Si intenta analizar una función stringificada, en realidad no le informa sobre los parámetros adicionales sin nombre que podría tomar.

Aquí hay una situación aún peor y más común. Si una función tiene más de 3 o 4 argumentos, podría ser lógico pasarle un objeto, lo que es más fácil de trabajar.

function saySomething(obj) { if(obj.message) console.log((obj.sender || "Anon") + ": " + obj.message); } saySomething({sender: "user123", message: "Hello world"});

En este caso, la función en sí podrá leer a través del objeto que recibe y buscar sus propiedades y obtener sus nombres y valores, pero tratar de analizar la representación de cadena de la función solo le dará "obj" para los parámetros, que no es útil en absoluto.


parámetro de función cadena imagen valor dinámicamente desde JSON . Dado que item.product_image2 es una cadena de URL, debe ponerla entre comillas cuando llame a changeImage en el parámetro.

Mi función onclick

items+=''<img src=''+item.product_image1+'' id="saleDetailDivGetImg">''; items+="<img src="+item.product_image2+" onclick=''changeImage(/""+item.product_image2+"/");''>";

Mi funcion

<script type="text/javascript"> function changeImage(img) { document.getElementById("saleDetailDivGetImg").src=img; alert(img); } </script>


A continuación te doy un breve ejemplo:

function test(arg1,arg2){ var funcStr = test.toString() var leftIndex = funcStr.indexOf(''(''); var rightIndex = funcStr.indexOf('')''); var paramStr = funcStr.substr(leftIndex+1,rightIndex-leftIndex-1); var params = paramStr.split('',''); for(param of params){ console.log(param); // arg1,arg2 } } test();


Aquí hay una forma:

// Utility function to extract arg name-value pairs function getArgs(args) { var argsObj = {}; var argList = //(([^)]*)/.exec(args.callee)[1]; var argCnt = 0; var tokens; var argRe = //s*([^,]+)/g; while (tokens = argRe.exec(argList)) { argsObj[tokens[1]] = args[argCnt++]; } return argsObj; } // Test subject function add(number1, number2) { var args = getArgs(arguments); console.log(args); // ({ number1: 3, number2: 4 }) } // Invoke test subject add(3, 4);

Nota: Esto solo funciona en los navegadores compatibles arguments.callee.


Cómo lo hago típicamente:

function name(arg1, arg2){ var args = arguments; // array: [arg1, arg2] var objecArgOne = args[0].one; } name({one: "1", two: "2"}, "string");

Puedes incluso refutar los argumentos por el nombre de las funciones como:

name.arguments;

¡Espero que esto ayude!


Es bastante facil

En la primera hay un desaprobado arguments.callee- una referencia a la función llamada. En la segunda, si tiene una referencia a su función, puede obtener fácilmente su representación textual. En el tercero, si llama a su función como constructor, también puede tener un enlace a través de suObject.constructor. NB: La primera solución está obsoleta, por lo que si no puede no usarla, también debe pensar en la arquitectura de su aplicación. Si no necesita nombres de variables exactos, solo use dentro de una función variable interna argumentssin ningún tipo de magia.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee

Todos ellos van a llamar a toString y reemplazar con re para que podamos crear un ayudante:

// getting names of declared parameters var getFunctionParams = function (func) { return String(func).replace(/[^/(]+/(([^/)]*)/).*/m, ''$1''); }

Algunos ejemplos:

// Solution 1. deprecated! don''t use it! var myPrivateFunction = function SomeFuncName (foo, bar, buz) { console.log(getFunctionParams(arguments.callee)); }; myPrivateFunction (1, 2); // Solution 2. var myFunction = function someFunc (foo, bar, buz) { // some code }; var params = getFunctionParams(myFunction); console.log(params); // Solution 3. var cls = function SuperKewlClass (foo, bar, buz) { // some code }; var inst = new cls(); var params = getFunctionParams(inst.constructor); console.log(params);

Disfruta con JS!

UPD: Jack Allan recibió una solución un poco mejor en realidad. GJ Jack!


Este paquete utiliza la refundición para crear un AST y luego los nombres de los parámetros se recopilan a partir de los mismos, esto le permite admitir la coincidencia de patrones, argumentos predeterminados, funciones de flecha y otras características de ES6.

https://www.npmjs.com/package/es-arguments


La respuesta a esto requiere 3 pasos:

  1. Para obtener los valores de los parámetros reales pasados ​​a la función (llamémosla argValues). Esto es sencillo ya que estará disponible argumentsdentro de la función.
  2. Para obtener los nombres de los parámetros de la firma de función (llamémoslo argNames). Esto no es tan fácil y requiere analizar la función. En lugar de hacer la expresión regular compleja usted mismo y preocuparse por los casos de borde (parámetros predeterminados, comentarios, ...), puede usar una biblioteca como Babylon que analizará la función en un árbol de sintaxis abstracta desde el que puede obtener los nombres de los parámetros.
  3. El último paso es unir las 2 matrices en una matriz que tenga el nombre y el valor de todos los parámetros.

El código será así.

const babylon = require("babylon") function doSomething(a, b, c) { // get the values of passed argumenst const argValues = arguments // get the names of the arguments by parsing the function const ast = babylon.parse(doSomething.toString()) const argNames = ast.program.body[0].params.map(node => node.name) // join the 2 arrays, by looping over the longest of 2 arrays const maxLen = Math.max(argNames.length, argValues.length) const args = [] for (i = 0; i < maxLen; i++) { args.push({name: argNames[i], value: argValues[i]}) } console.log(args) // implement the actual function here } doSomething(1, 2, 3, 4)

y el objeto registrado será

[ { "name": "a", "value": 1 }, { "name": "c", "value": 3 }, { "value": 4 } ]

Y aquí hay un ejemplo https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a


No sé cómo obtener una lista de los parámetros, pero puede hacer esto para obtener la cantidad que espera.

alert(doSomething.length);


Nota: si desea utilizar la desestructuración de parámetros ES6 con la solución superior, agregue la siguiente línea.

if (result[0] === ''{'' && result[result.length - 1 === ''}'']) result = result.slice(1, -1)


Puede acceder a los valores de argumento pasados ​​a una función utilizando la propiedad "argumentos".

function doSomething() { var args = doSomething.arguments; var numArgs = args.length; for(var i = 0 ; i < numArgs ; i++) { console.log("arg " + (i+1) + " = " + args[i]); //console.log works with firefox + firebug // you can use an alert to check in other browsers } } doSomething(1, ''2'', {A:2}, [1,2,3]);


Cualquiera que sea la solución, no debe interrumpir las funciones extrañas, cuyo toString()aspecto es tan extraño:

function ( A, b ,c ,d ){}

Además, ¿por qué usar expresiones regulares complejas? Esto se puede hacer como:

function getArguments(f) { return f.toString().split('')'',1)[0].replace(//s/g,'''').substr(9).split('',''); }

Esto funciona en todas partes con cada función, y la única expresión regular es la eliminación de espacios en blanco que ni siquiera procesa toda la cadena debido al .splittruco.


He modificado la versión tomada de AngularJS que implementa un mecanismo de inyección de dependencia para trabajar sin Angular. También he actualizado la STRIP_COMMENTSexpresión regular para trabajar ECMA6, por lo que admite cosas como los valores predeterminados en la firma.

var FN_ARGS = /^function/s*[^/(]*/(/s*([^/)]*)/)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^/s*(_?)(.+?)/1/s*$/; var STRIP_COMMENTS = /(////.*$)|(///*[/s/S]*?/*//)|(/s*=[^,/)]*((''(?://'|[^''/r/n])*'')|("(?://"|[^"/r/n])*"))|(/s*=[^,/)]*))/mg; function annotate(fn) { var $inject, fnText, argDecl, last; if (typeof fn == ''function'') { if (!($inject = fn.$inject)) { $inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''''); argDecl = fnText.match(FN_ARGS); argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) { arg.replace(FN_ARG, function(all, underscore, name) { $inject.push(name); }); }); fn.$inject = $inject; } } else { throw Error("not a function") } return $inject; } console.log("function(a, b)",annotate(function(a, b) { console.log(a, b, c, d) })) console.log("function(a, b = 0, /*c,*/ d)",annotate(function(a, b = 0, /*c,*/ d) { console.log(a, b, c, d) })) annotate({})


La forma correcta de hacer esto es usar un analizador JS. Aquí hay un ejemplo usando acorn .

const acorn = require(''acorn''); function f(a, b, c) { // ... } const argNames = acorn.parse(f).body[0].params.map(x => x.name); console.log(argNames); // Output: [ ''a'', ''b'', ''c'' ]

El código aquí encuentra los nombres de los tres parámetros (formales) de la función f. Lo hace mediante la alimentación fen acorn.parse().


Ok, entonces una vieja pregunta con muchas respuestas adecuadas. Aquí está mi oferta que no usa expresiones regulares, a excepción de la pequeña tarea de eliminar espacios en blanco. (Debo tener en cuenta que la función "strips_comments" en realidad los aleja, en lugar de eliminarlos físicamente. Eso se debe a que lo uso en otros lugares y por varias razones, las ubicaciones de los tokens originales sin comentarios deben permanecer intactos)

Es un bloque de código bastante largo ya que este pegado incluye un marco de prueba mini.

function do_tests(func) { if (typeof func !== ''function'') return true; switch (typeof func.tests) { case ''undefined'' : return true; case ''object'' : for (var k in func.tests) { var test = func.tests[k]; if (typeof test===''function'') { var result = test(func); if (result===false) { console.log(test.name,''for'',func.name,''failed''); return false; } } } return true; case ''function'' : return func.tests(func); } return true; } function strip_comments(src) { var spaces=(s)=>{ switch (s) { case 0 : return ''''; case 1 : return '' ''; case 2 : return '' ''; default : return Array(s+1).join('' ''); } }; var c1 = src.indexOf (''/*''), c2 = src.indexOf (''//''), eol; var out = ""; var killc2 = () => { out += src.substr(0,c2); eol = src.indexOf(''/n'',c2); if (eol>=0) { src = spaces(eol-c2)+''/n''+src.substr(eol+1); } else { src = spaces(src.length-c2); return true; } return false; }; while ((c1>=0) || (c2>=0)) { if (c1>=0) { // c1 is a hit if ( (c1<c2) || (c2<0) ) { // and it beats c2 out += src.substr(0,c1); eol = src.indexOf(''*/'',c1+2); if (eol>=0) { src = spaces((eol-c1)+2)+src.substr(eol+2); } else { src = spaces(src.length-c1); break; } } else { if (c2 >=0) { // c2 is a hit and it beats c1 if (killc2()) break; } } } else { if (c2>=0) { // c2 is a hit, c1 is a miss. if (killc2()) break; } else { // both c1 & c2 are a miss break; } } c1 = src.indexOf (''/*''); c2 = src.indexOf (''//''); } return out + src; } function function_args(fn) { var src = strip_comments(fn.toString()); var names=src.split('')'')[0].replace(//s/g,'''').split(''('')[1].split('',''); return names; } function_args.tests = [ function test1 () { function/*al programmers will sometimes*/strip_comments_tester/* because some comments are annoying*/( /*see this---(((*/ src//)) it''s an annoying comment does not help anyone understand if the ,code,//really does /**/sucks ,much /*?*/)/*who would put "comment/" about a function like (this) { comment } here?*/{ } var data = function_args(strip_comments_tester); return ( (data.length==4) && (data[0]==''src'') && (data[1]==''code'') && (data[2]==''sucks'') && (data[3]==''much'') ); } ]; do_tests(function_args);


Tomando la answer de @ jack-allan, modifiqué ligeramente la función para permitir las propiedades predeterminadas de ES6, como:

function( a, b = 1, c ){};

todavía regresar [ ''a'', ''b'' ]

/** * Get the keys of the paramaters of a function. * * @param {function} method Function to get parameter keys for * @return {array} */ var STRIP_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; var ARGUMENT_NAMES = /(?:^|,)/s*([^/s,=]+)/g; function getFunctionParameters ( func ) { var fnStr = func.toString().replace(STRIP_COMMENTS, ''''); var argsList = fnStr.slice(fnStr.indexOf(''('')+1, fnStr.indexOf('')'')); var result = argsList.match( ARGUMENT_NAMES ); if(result === null) { return []; } else { var stripped = []; for ( var i = 0; i < result.length; i++ ) { stripped.push( result[i].replace(/[/s,]/g, '''') ); } return stripped; } }


Wow tantas respuestas ya ... Estoy bastante seguro de que esto se entierra. Aun así, pensé que esto podría ser útil para algunos.

No estaba completamente satisfecho con las respuestas elegidas, ya que en ES6 no funciona bien con los valores predeterminados. Y tampoco proporciona la información del valor predeterminado. También quería una función ligera que no dependiera de una biblioteca externa.

Esta función es muy útil para fines de depuración, por ejemplo: registrar una función llamada con sus parámetros, valores de parámetros predeterminados y argumentos.

Pasé un tiempo en esto ayer, descifrando el RegExp correcto para resolver este problema y esto es lo que se me ocurrió. Funciona muy bien y estoy muy satisfecho con el resultado:

const REGEX_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; const REGEX_FUNCTION_PARAMS = /(?:/s*(?:function/s*[^(]*)?/s*)((?:[^''"]|(?:(?:([''"])(?:(?:.*?[^//]/2)|/2))))*?)/s*(?=(?:=>)|{)/m const REGEX_PARAMETERS_VALUES = //s*(/w+)/s*(?:=/s*((?:(?:([''"])(?:/3|(?:.*?[^//]/3)))((/s*/+/s*)(?:(?:([''"])(?:/6|(?:.*?[^//]/6)))|(?:[/w$]*)))*)|.*?))?/s*(?:,|$)/gm /** * Retrieve a function''s parameter names and default values * Notes: * - parameters with default values will not show up in transpiler code (Babel) because the parameter is removed from the function. * - does NOT support inline arrow functions as default values * to clarify: ( name = "string", add = defaultAddFunction ) - is ok * ( name = "string", add = ( a )=> a + 1 ) - is NOT ok * - does NOT support default string value that are appended with a non-standard ( word characters or $ ) variable name * to clarify: ( name = "string" + b ) - is ok * ( name = "string" + $b ) - is ok * ( name = "string" + b + "!" ) - is ok * ( name = "string" + λ ) - is NOT ok * @param {function} func * @returns {Array} - An array of the given function''s parameter [key, default value] pairs. */ function getParams(func) { let functionAsString = func.toString() let params = [] let match functionAsString = functionAsString.replace(REGEX_COMMENTS, '''') functionAsString = functionAsString.match(REGEX_FUNCTION_PARAMS)[1] if (functionAsString.charAt(0) === ''('') functionAsString = functionAsString.slice(1, -1) while (match = REGEX_PARAMETERS_VALUES.exec(functionAsString)) params.push([match[1], match[2]]) return params } // Lets run some tests! var defaultName = ''some name'' function test1(param1, param2, param3) { return (param1) => param1 + param2 + param3 } function test2(param1, param2 = 4 * (5 / 3), param3) {} function test3(param1, param2 = "/root/" + defaultName + ".jpeg", param3) {} function test4(param1, param2 = (a) => a + 1) {} console.log(getParams(test1)) console.log(getParams(test2)) console.log(getParams(test3)) console.log(getParams(test4)) // [ [ ''param1'', undefined ], [ ''param2'', undefined ], [ ''param3'', undefined ] ] // [ [ ''param1'', undefined ], [ ''param2'', ''4 * (5 / 3)'' ], [ ''param3'', undefined ] ] // [ [ ''param1'', undefined ], [ ''param2'', ''"/root/" + defaultName + ".jpeg"'' ], [ ''param3'', undefined ] ] // [ [ ''param1'', undefined ], [ ''param2'', ''( a'' ] ] // --> This last one fails because of the inlined arrow function! var arrowTest1 = (a = 1) => a + 4 var arrowTest2 = a => b => a + b var arrowTest3 = (param1 = "/" + defaultName) => { return param1 + ''...'' } var arrowTest4 = (param1 = "/" + defaultName, param2 = 4, param3 = null) => { () => param3 ? param3 : param2 } console.log(getParams(arrowTest1)) console.log(getParams(arrowTest2)) console.log(getParams(arrowTest3)) console.log(getParams(arrowTest4)) // [ [ ''a'', ''1'' ] ] // [ [ ''a'', undefined ] ] // [ [ ''param1'', ''"/" + defaultName'' ] ] // [ [ ''param1'', ''"/" + defaultName'' ], [ ''param2'', ''4'' ], [ ''param3'', ''null'' ] ] console.log(getParams((param1) => param1 + 1)) console.log(getParams((param1 = ''default'') => { return param1 + ''.jpeg'' })) // [ [ ''param1'', undefined ] ] // [ [ ''param1'', ''/'default/''' ] ]

Como puede ver, algunos de los nombres de parámetros desaparecen porque el transpiler de Babel los elimina de la función. Si ejecuta esto en el último NodeJS, funciona como se esperaba (los resultados comentados son de NodeJS).

Otra nota, como se indica en el comentario, es que no funciona con las funciones de flecha en línea como un valor predeterminado. Esto simplemente hace que sea demasiado complejo extraer los valores utilizando un RegExp.

Por favor, hágamelo saber si esto fue útil para usted! Me encantaría escuchar algunos comentarios!


function getArguments(func) { const ARROW = true; const FUNC_ARGS = ARROW ? /^(function)?/s*[^/(]*/(/s*([^/)]*)/)/m : /^(function)/s*[^/(]*/(/s*([^/)]*)/)/m; const FUNC_ARG_SPLIT = /,/; const FUNC_ARG = /^/s*(_?)(.+?)/1/s*$/; const STRIP_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; return ((func || '''').toString().replace(STRIP_COMMENTS, '''').match(FUNC_ARGS) || ['''', '''', ''''])[2] .split(FUNC_ARG_SPLIT) .map(function(arg) { return arg.replace(FUNC_ARG, function(all, underscore, name) { return name.split(''='')[0].trim(); }); }) .filter(String); } ////////// TESTS ////////// function logArgs(func) { let object = {}; object[func] = getArguments(func); console.log(object); // console.log(/*JSON.stringify(*/getArguments(func)/*)*/); } console.log(''''); console.log(''////////// MISC //////////''); logArgs((a, b) => {}); logArgs((a, b = 1) => {}); logArgs((a, b, ...args) => {}); logArgs(function(a, b, ...args) {}); logArgs(function(a, b = 1, c = 4 * (5 / 3), d = 2) {}); logArgs(async function(a, b, ...args) {}); logArgs(function async(a, b, ...args) {}); console.log(''''); console.log(''////////// FUNCTIONS //////////''); logArgs(function(a, b, c) {}); logArgs(function() {}); logArgs(function named(a, b, c) {}); logArgs(function(a /* = 1 */, b /* = true */) {}); logArgs(function fprintf(handle, fmt /*, ...*/) {}); logArgs(function(a, b = 1, c) {}); logArgs(function(a = 4 * (5 / 3), b) {}); // logArgs(function (a, // single-line comment xjunk) {}); // logArgs(function (a /* fooled you {}); // logArgs(function (a /* function() yes */, /n /* no, */b)/* omg! */ {}); // logArgs(function ( A, b /n,c ,d /n ) /n {}); logArgs(function(a, b) {}); logArgs(function $args(func) {}); logArgs(null); logArgs(function Object() {}); console.log(''''); console.log(''////////// STRINGS //////////''); logArgs(''function (a,b,c) {}''); logArgs(''function () {}''); logArgs(''function named(a, b, c) {}''); logArgs(''function (a /* = 1 */, b /* = true */) {}''); logArgs(''function fprintf(handle, fmt /*, ...*/) {}''); logArgs(''function( a, b = 1, c ) {}''); logArgs(''function (a=4*(5/3), b) {}''); logArgs(''function (a, // single-line comment xjunk) {}''); logArgs(''function (a /* fooled you {}''); logArgs(''function (a /* function() yes */, /n /* no, */b)/* omg! */ {}''); logArgs(''function ( A, b /n,c ,d /n ) /n {}''); logArgs(''function (a,b) {}''); logArgs(''function $args(func) {}''); logArgs(''null''); logArgs(''function Object() {}'');

=> ["a", "b", "c"]


//See this: // global var, naming bB var bB = 5; // Dependency Injection cokntroller var a = function(str, fn) { //stringify function body var fnStr = fn.toString(); // Key: get form args to string var args = fnStr.match(/function/s*/((.*?)/)/); // console.log(args); // if the form arg is ''bB'', then exec it, otherwise, do nothing for (var i = 0; i < args.length; i++) { if(args[i] == ''bB'') { fn(bB); } } } // will do nothing a(''sdfdfdfs,'', function(some){ alert(some) }); // will alert 5 a(''sdfdsdsfdfsdfdsf,'', function(bB){ alert(bB) }); // see, this shows you how to get function args in string


function getArgs(args) { var argsObj = {}; var argList = //(([^)]*)/.exec(args.callee)[1]; var argCnt = 0; var tokens; while (tokens = //s*([^,]+)/g.exec(argList)) { argsObj[tokens[1]] = args[argCnt++]; } return argsObj; }