2010-07-04 27 views
27

Estoy usando Javascript con jQuery. Me gustaría implementar parámetros. En C#, se vería algo como esto:¿Cuál es la mejor manera de implementar params en JavaScript?

/* 
* odp  the object to test 
* error a string that will be filled with the error message if odp is illegal. Undefined otherwise. 
* 
* Returns true if odp is legal. 
*/ 
bool isLegal(odp, out error); 

¿Cuál es la mejor manera de hacer algo como esto en JS? ¿Objetos?

function isLegal(odp, errorObj) 
{ 
    // ... 
    errorObj.val = "ODP failed test foo"; 
    return false; 
} 

Firebug me dice que el enfoque anterior funcionaría, pero ¿hay una mejor manera?

+0

Nick, Sé que fue hace un tiempo, pero creo que finalmente tengo una [respuesta] (https://stackoverflow.com/a/48517986/1016343) para ti. Sí puede hacer parámetros en JavaScript. – Matt

Respuesta

13

Creo que esta es la única manera (pero no soy un programador de JavaScript hardcore;)).

Lo que también podría considerar es el uso de una función de devolución de llamada:

function onError(data) { 
    // do stuff 
} 


function isLegal(odp, cb) { 
    //... 
    if(error) cb(error); 
    return false; 
} 

isLegal(value, onError); 
+1

+1, este es el enfoque más funcional, sin embargo, requiere que maneje el error de inmediato. También es el más común en mi experiencia. – gradbot

33

El método de devolución de llamada mencionada por @Felix Kling es probablemente la mejor idea, pero también me he dado cuenta que a veces es fácil de aprovechar Javascript objetar la sintaxis literal y sólo tienen la función devuelve un objeto en el error:

function mightFail(param) { 
    // ... 
    return didThisFail ? { error: true, msg: "Did not work" } : realResult; 
} 

a continuación, cuando se llama a la función:

var result = mightFail("something"); 
if (result.error) alert("It failed: " + result.msg); 

No es lujoso y apenas a prueba de balas, pero ciertamente está bien para algunas situaciones simples.

+0

+1, este enfoque es común en las llamadas JSON pero rara vez lo he visto en el código. – gradbot

+1

+1 Me gusta esto ... – Julien

+1

Al haber llegado a esta página porque estaba interesado en cómo Javascript podría o no manejar los parámetros, estoy decepcionado con la respuesta aceptada. La capacidad de tener un tipo de retorno definido junto con uno a muchos parámetros de salida con tipos definidos es muy poderosa cuando se programa una lógica muy procesal. Desafortunadamente, con mi pequeña reputación no puedo votar. –

13

Sí, como usted mismo ha mencionado, los objetos son la mejor y única forma de pasar datos por referencia en JavaScript. Me gustaría mantener su función como tal isLegal y simplemente lo llamo así:

var error = {}; 
isLegal("something", error); 
alert(error.val); 
+1

+1, este estilo es lo más cercano que vas a llegar a C#. – gradbot

+0

esto es genial ... –

3

hay otra manera JS puede pasar 'hacia fuera' parámetros. pero creo que los mejores para su situación ya fueron mencionados.

Las matrices también se pasan por referencia, no por valor. así como puede pasar un objeto a una función, y luego establecer una propiedad del objeto en la función, y luego regresar, y acceder a la propiedad de ese objeto, de manera similar puede pasar una matriz a una función, establecer algunos valores de la matriz dentro de la función, y regresar y acceder a esos valores fuera de la matriz.

así que en cada situación puede preguntarse, "¿es mejor una matriz o un objeto?"

+0

aunque esto es posible, por claridad de código en el código de llamada, recomendaría la respuesta de @Pointy: utilice un valor de retorno sobrecargado ya que es marginalmente más claro. – cmroanirgo

1

no voy a publicar ningún code pero lo que deja de hacer aquí en estas respuestas es rima poner a la razón. Estoy trabajando en la arena JS nativa y surgió el problema de que algunos native API calls necesitan ser transformados porque no podemos escribir en los parámetros sin feos hacks vergonzosos.

Esta es mi solución:

// Functions that return parameter data should be modified to return 
    // an array whose zeroeth member is the return value, all other values 
    // are their respective 1-based parameter index. 

That doesn't mean define and return every parameter. Only the parameters that recieve output.

La razón de este enfoque es así: Multiple return values puede ser necesaria para cualquier número de procedimientos. Esto crea una situación en la que los objetos con valores con nombre (que en última instancia no estarán sincronizados con el contexto léxico de todas las operaciones), constantemente, deben ser memorizados para poder trabajar de manera apropiada con el procedimiento (s).

Utilizando el método prescrito, es suficiente con saber what you called, y en lugar de where you should be lookingtener que saber lo que está buscando.

También existe la ventaja de que los "robustos y estúpidos" alogrithms se pueden escribir para envolver alrededor de las llamadas de procedimiento deseadas para hacer esta operación "más transparente".

Sería aconsejable utilizar una object, function, o un array (todos los cuales son objetos) como parámetro "write-back-producto", pero yo creo que si cualquier trabajo ajeno se debe hacer, lo que debería se debe hacer por el que escribe el kit de herramientas para facilitar las cosas o ampliar la funcionalidad.

Esta es una respuesta única para cada occaision, que mantiene el aspecto de APIs a primera vista, en lugar de parecer ser y tener toda la semejanza de un tejido de código de spaghetti con un entramado indefinido que no puede descifrar si es una definición o datos.

Enhorabuena y buena suerte.

Estoy usando el webkitgtk3 e interconecto algunos proxios nativos de C Library. por lo que esta muestra de código probado podría al menos servir al propósito de ilustración.

// ssize_t read(int filedes, void *buf, size_t nbyte) 
SeedValue libc_native_io_read (SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) { 


    // NOTE: caller is completely responsible for buffering! 

        /* C CODING LOOK AND FEEL */ 


    if (argument_count != 3) { 
     seed_make_exception (ctx, exception, xXx_native_params_invalid, 
      "read expects 3 arguments: filedes, buffer, nbyte: see `man 3 read' for details", 
      argument_count 
     ); return seed_make_undefined (ctx); 
    } 

    gint filedes = seed_value_to_int(ctx, arguments[0], exception); 
    void *buf = seed_value_to_string(ctx, arguments[1], exception); 
    size_t nbyte = seed_value_to_ulong(ctx, arguments[2], exception); 

    SeedValue result[3]; 

    result[0] = seed_value_from_long(ctx, read(filedes, buf, nbyte), exception); 
    result[2] = seed_value_from_binary_string(ctx, buf, nbyte, exception); 

    g_free(buf); 
    return seed_make_array(ctx, result, 3, exception); 

} 
+0

Esta es una excelente idea para devolver los parámetros en JavaScript. Tiene más sentido para mí. – Sunil

1

El siguiente es el enfoque que estoy usando. Y esta es la respuesta para esta pregunta. Sin embargo, el código no ha sido probado.

function mineCoords(an_x1, an_y1) { 
    this.x1 = an_x1; 
    this.y1 = an_y1; 
} 

function mineTest(an_in_param1, an_in_param2) { 

    // local variables 
    var lo1 = an_in_param1; 
    var lo2 = an_in_param2; 

    // process here lo1 and lo2 and 
    // store result in lo1, lo2 

    // set result object 
    var lo_result = new mineCoords(lo1, lo2); 
    return lo_result; 
} 

var lo_test = mineTest(16.7, 22.4); 
alert('x1 = ' + lo_test.x1.toString() + ', y1 = ' + lo_test.y1.toString()); 
2

estoy usando un método de devolución de llamada (similar a Felix Kling's approach) para simular el comportamiento de los parámetros out. Mi respuesta difiere de la de Kling en que la función de devolución de llamada actúa como un cierre de captura de referencia en lugar de un controlador.

Este enfoque adolece de la sintaxis de la función anónima detallada de JavaScript, pero reproduce de cerca la semántica de parámetros de otros idiomas.

function isLegal(odp, out_error) { 
    //... 
    out_error("ODP failed test foo"); // Assign to out parameter. 
    return false; 
} 

var error; 
var success = isLegal(null, function (e) { error = e; }); 

// Invariant: error === "ODP failed test foo". 
0

El método usual para el caso específico el uso que se describe en Javascript, y de hecho los idiomas más alto nivel, es confiar en errores (también conocido como excepciones) para hacerle saber cuando ha ocurrido algo fuera de lo común. No hay forma de pasar un tipo de valor (cadenas, números, etc.) por referencia en Javascript.

Simplemente lo haría. Si realmente necesita enviar datos personalizados a la función de llamada, puede crear una subclase Error.

var MyError = function (message, some_other_param) 
{ 
    this.message = message; 
    this.some_other_param = some_other_param; 
} 
//I don't think you even need to do this, but it makes it nice and official 
MyError.prototype = Error; 
... 
if (something_is_wrong) 
    throw new MyError('It failed', /* here's a number I made up */ 150); 

La captura de excepciones es un dolor, lo sé, pero de nuevo también lo es hacer un seguimiento de las referencias.

Si realmente necesita algo que se acerca al comportamiento de las variables fuera, los objetos se pasan por referencia por defecto, y cómodamente pueden capturar datos de otros scopes--

function use_out (outvar) 
{ 
    outvar.message = 'This is my failure'; 
    return false; 
} 

var container = { message : '' }; 
var result = use_out(container); 
console.log(container.message); ///gives the string above 
console.log(result); //false 

Creo que esto va un algunas formas de responder a su pregunta, pero creo que su enfoque completo está roto desde el principio.Javascript admite muchas formas mucho más elegantes y potentes de obtener múltiples valores de una función. Leer un poco sobre generadores, cierres, incluso retrollamadas, puede ser bueno en ciertas situaciones, busque el estilo de continuación de paso.

Mi punto con esta diatriba es animar a cualquiera que lea esto a adaptar su estilo de programación a las limitaciones y capacidades del lenguaje que está utilizando, en lugar de intentar forzar lo que aprendió de otros idiomas.

(Por cierto que algunas personas recomiendan firmemente contra los cierres debido a que causan malos efectos secundarios, pero no escucharon a ellos. Son los puristas. Los efectos secundarios son casi inevitables en una gran cantidad de aplicaciones sin mucho tedioso retroceder y caminar alrededor de obstáculos que no pueden llegar desde allí. Si los necesita, mantenerlos todos juntos en un ámbito léxico ordenado en lugar de esparcidos por todo un infierno de punteros oscuros y referencias me suena mucho mejor)

0

Las respuestas que he visto hasta ahora no están implementando parámetros en JavaScript, ya que se usan en C# (la palabra clave out). Son simplemente una solución que devuelve un objeto en caso de error.

Pero, ¿qué hace si realmente necesita los parámetros?

Como Javascript no lo admite directamente, debe crear algo que esté cerca de los parámetros de C# out. Eche un vistazo a este enfoque, estoy emulando la función DateTime.TryParse de C# en JavaScript. El parámetro de salida es consecuencia, y debido JavaScript no proporciona una palabra clave out, estoy usando .value dentro de la función para pasar el valor fuera de la función (como inspirados por MDN suggestion):

// create a function similar to C#'s DateTime.TryParse 
 
var DateTime = []; 
 
DateTime.TryParse = function(str, result) { 
 
    result.value = new Date(str); // out value 
 
    return (result.value != "Invalid Date"); 
 
}; 
 

 
// now invoke it 
 
var result = []; 
 
if (DateTime.TryParse("05.01.2018", result)) { 
 
    alert(result.value); 
 
} else { 
 
    alert("no date"); 
 
};

Ejecute el fragmento y verá que funciona. Tenga en cuenta que result debe inicializarse como matriz vacía [], antes de llamar a la función. Esto es necesario porque dentro de la función "inyecta" la propiedad .value.


Ahora puede utilizar el patrón de arriba para escribir una función como la de su pregunta (esto también se muestra cómo emular el nuevo parámetro de descartes out _ en C#):

// create a function similar to C#'s DateTime.TryParse 
 
var DateTime = []; 
 
DateTime.TryParse = function(str, result) { 
 
    result.value = new Date(str); // out value 
 
    return (result.value != "Invalid Date"); 
 
}; 
 

 
// returns false, if odb is no date, otherwise true 
 
function isLegal(odp, errorObj) { 
 
    if (DateTime.TryParse(odp, [])) { // discard result here by passing [] 
 
    // all OK: leave errorObj.value undefined and return true 
 
    return true; 
 
    } else { 
 
    errorObj.value = "ODP failed test foo"; // return error 
 
    return false; 
 
    } 
 
} 
 

 
// now test the function 
 
var odp = "xxx01.12.2018xx"; // invalid date 
 
var errorObj = []; 
 
if (!isLegal(odp, errorObj)) alert(errorObj.value); else alert("OK!");

Nota: en lugar de utilizar un parámetro de descarte como se muestra arriba, en JavaScript que podría ALS o El uso de un cheque por undefined, es decir, dentro de la función comprueba

if (result === undefined) { 
    // do the check without passing back a value, i.e. just return true or false 
}; 

Entonces es posible omitir result como parámetro por completo si no es necesario, por lo que podría invocarla como

if (DateTime.TryParse(odp)) { 
    // ... same code as in the snippet above ... 
}; 
Cuestiones relacionadas