llamar - Parámetros con nombre en javascript
manual de javascript completo pdf (7)
En algunos casos, considero que la característica de parámetros nombrados en C # es bastante útil.
calculateBMI(70, height: 175);
¿Qué pasa si quiero esto en javascript ?
Lo que no quiero es -
myFunction({ param1 : 70, param2 : 175});
function myFunction(params){
//check if params is an object
//check if the parameters I need are non-null
//blah-blah
}
Ese enfoque que ya he usado. ¿Hay otra manera?
Estoy bien usando cualquier biblioteca, haz esto. (O alguien me puede señalar uno que ya lo hace)
Este problema ha sido un problema mío durante algún tiempo. Soy un programador experimentado con muchos idiomas en mi haber. Uno de mis idiomas favoritos que he tenido el placer de usar es Python. Python admite parámetros con nombre sin ningún truco ... Desde que comencé a usar Python (hace un tiempo) todo se volvió más fácil. Creo que cada idioma debe soportar parámetros con nombre, pero ese no es el caso.
Mucha gente dice que solo use el truco "Pase un objeto" para que tenga parámetros con nombre.
/**
* My Function
*
* @param {Object} arg1 Named arguments
*/
function myFunc(arg1) { }
myFunc({ param1 : 70, param2 : 175});
Y eso funciona muy bien, excepto ..... cuando se trata de la mayoría de los IDE que existen, muchos de nosotros los desarrolladores confiamos en sugerencias de tipo / argumento dentro de nuestro IDE. Personalmente utilizo PHP Storm (junto con otros IDE de JetBrains como PyCharm para Python y AppCode para Objective C)
Y el mayor problema con el uso del truco de "Pasar un objeto" es que cuando llamas a la función, el IDE te da una pista de un solo tipo y eso es todo ... ¿Cómo se supone que debemos saber qué parámetros y tipos deberían incluirse en el arg1 objeto?
Entonces ... el truco de "Pasar un objeto" no funciona para mí ... En realidad causa más dolores de cabeza al tener que mirar el docblock de cada función antes de saber qué parámetros espera la función ... Claro, es genial para cuando mantiene código existente, pero es horrible escribir código nuevo.
Bueno, esta es la técnica que uso ... Ahora, puede haber algunos problemas con ella, y algunos desarrolladores pueden decirme que lo estoy haciendo mal, y tengo una mente abierta cuando se trata de estas cosas ... Siempre estoy dispuesto a buscar mejores formas de llevar a cabo una tarea ... Entonces, si hay un problema con esta técnica, entonces los comentarios son bienvenidos.
/**
* My Function
*
* @param {string} arg1 Argument 1
* @param {string} arg2 Argument 2
*/
function myFunc(arg1, arg2) { }
var arg1, arg2;
myFunc(arg1=''Param1'', arg2=''Param2'');
De esta manera, tengo lo mejor de ambos mundos ... el código nuevo es fácil de escribir ya que mi IDE me da todos los consejos de argumento adecuados ... Y, aunque mantengo el código más adelante, puedo ver de un vistazo, no solo el valor pasado a la función, pero también el nombre del argumento. La única sobrecarga que veo es declarar los nombres de tus argumentos como variables locales para evitar contaminar el espacio de nombres global. Claro, es un poco más de tipeo, pero trivial en comparación con el tiempo que lleva buscar docblocks mientras escribes un código nuevo o mantienes el código existente.
Hay otra manera. Si pasa un objeto por referencia, las propiedades de ese objeto aparecerán en el alcance local de la función. Sé que esto funciona para Safari (no he comprobado otros navegadores) y no sé si esta característica tiene un nombre, pero el siguiente ejemplo ilustra su uso.
Aunque en la práctica no creo que esto ofrezca ningún valor funcional más allá de la técnica que ya está utilizando, es un poco más semántico. Y aún requiere pasar una referencia de objeto o un objeto literal.
function sum({ a:a, b:b}) {
console.log(a+''+''+b);
if(a==undefined) a=0;
if(b==undefined) b=0;
return (a+b);
}
// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));
// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));
Otra forma sería usar atributos de un objeto adecuado, por ejemplo, así:
function plus(a,b) { return a+b; };
Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}},
b: function(y) { return { a: function(x) { return plus(x,y) }}}};
sum = Plus.a(3).b(5);
Por supuesto, para este ejemplo inventado, es algo sin sentido. Pero en los casos donde la función se ve como
do_something(some_connection_handle, some_context_parameter, some_value)
podría ser más útil. También podría combinarse con la idea de "parameterfy" para crear dicho objeto a partir de una función existente de una manera genérica. Es decir, para cada parámetro crearía un miembro que puede evaluar una versión de evaluación parcial de la función.
Esta idea está, por supuesto, relacionada con Schönfinkeling también conocido como Currying.
Probando Node-6.4.0 (process.versions.v8 = ''5.0.71.60'') y Node Chakracore-v7.0.0-pre8 y luego Chrome-52 (V8 = 5.2.361.49), he notado que los parámetros nombrados son casi implementado, pero ese orden aún tiene prioridad. No puedo encontrar lo que dice el estándar ECMA.
>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }
> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17
¡Pero se requiere orden! ¿Es el comportamiento estándar?
> f(b=10)
a=10 + b=2 = 12
Si desea dejar en claro cuáles son cada uno de los parámetros, en lugar de solo llamar
someFunction(70, 115);
por qué no hacer lo siguiente
var width = 70, height = 115;
someFunction(width, height);
seguro, es una línea adicional de código, pero gana en legibilidad.
ES2015
En ES2015, la desestructuración de parámetros se puede usar para simular parámetros con nombre. Se requeriría que la persona que llama pase un objeto, pero puede evitar todas las comprobaciones dentro de la función si también usa parámetros predeterminados:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...
}
ES5
Hay una forma de acercarse a lo que desea, pero se basa en el resultado de Function.prototype.toString
[ES5] , que depende de la implementación hasta cierto punto, por lo que podría no ser compatible con varios navegadores.
La idea es analizar los nombres de los parámetros de la representación de cadena de la función para que pueda asociar las propiedades de un objeto con el parámetro correspondiente.
Una llamada a la función podría verse así
func(a, b, {someArg: ..., someOtherArg: ...});
donde a
y b
son argumentos posicionales y el último argumento es un objeto con argumentos nombrados.
Por ejemplo:
var parameterfy = (function() {
var pattern = /function[^(]*/(([^)]*)/)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,/s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === ''object'') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
Que usarías como:
var foo = parameterfy(function(a, b, c) {
console.log(''a is '' + a, '' | b is '' + b, '' | c is '' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
Hay algunos inconvenientes en este enfoque (¡ha sido advertido!):
- Si el último argumento es un objeto, se trata como un "objeto de argumento nombrado"
- Siempre obtendrá tantos argumentos como haya definido en la función, pero algunos de ellos pueden tener el valor
undefined
(que es diferente de no tener ningún valor). Eso significa que no puede usararguments.length
para probar cuántos argumentos se han pasado.
En lugar de tener una función para crear el contenedor, también podría tener una función que acepte una función y varios valores como argumentos, como
call(func, a, b, {posArg: ... });
o incluso extienda Function.prototype
para que pueda hacer:
foo.execute(a, b, {posArg: ...});
No , el enfoque del objeto es la respuesta de JavaScript a esto. No hay problema con esto siempre que su función espere un objeto en lugar de params separados.