valor - ¿Cómo puedo preestablecer argumentos en la llamada a función de JavaScript?(Aplicación de función parcial)
retornar valor de una funcion javascript (7)
Estoy intentando escribir una función de JavaScript que devolverá su primer argumento (función) con todos los demás argumentos como parámetros preestablecidos para esa función.
Asi que:
function out(a, b) { document.write(a + " " + b); } function setter(...) {...} setter(out, "hello")("world"); setter(out, "hello", "world")();
Saldría "hola mundo" dos veces. para alguna implementación de setter
Me encontré con un problema con la manipulación de la matriz de argumentos en mi primer intento, pero parece que habría una mejor manera de hacerlo.
** EDIT: ver la respuesta de Jason Bunting. De hecho, esta respuesta muestra una forma sub-par de encadenar numerosas llamadas salientes, no una única llamada saliente con preajustes para algunos de los argumentos. Si esta respuesta realmente ayuda con un problema similar, debe asegurarse de utilizar apply y call como Jason recomienda, en lugar de la forma oscura de usar eval que pensé. **
Bueno ... tu salida realmente escribirá mucho "indefinido" en esto ... pero esto debería estar cerca de lo que deseas:
function out(a, b) {
document.write(a + " " + b);
}
function getArgString( args, start ) {
var argStr = "";
for( var i = start; i < args.length; i++ ) {
if( argStr != "" ) {
argStr = argStr + ", ";
}
argStr = argStr + "arguments[" + i + "]"
}
return argStr;
}
function setter(func) {
var argStr = getArgString( arguments, 1 );
eval( "func( " + argStr + ");" );
var newSettter = function() {
var argStr = getArgString( arguments, 0 );
if( argStr == "" ) {
argStr = "func";
} else {
argStr = "func, " + argStr;
}
return eval( "setter( " + argStr + ");" );
}
return newSettter;
}
setter(out, "hello")("world");
setter(out, "hello", "world")();
Sin embargo, probablemente movería el código en getArgString a la función setter misma ... un poco más seguro ya que usé ''eval''s''.
Antes que nada, necesitas un parcial - hay una diferencia entre un parcial y un curry - y aquí está todo lo que necesitas, sin un marco :
function partial(func /*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(this, allArguments);
};
}
Ahora, usando su ejemplo, puede hacer exactamente lo que está buscando:
partial(out, "hello")("world");
partial(out, "hello", "world")();
// and here is my own extended example
var sayHelloTo = partial(out, "Hello");
sayHelloTo("World");
sayHelloTo("Alex");
La función partial()
podría utilizarse para implementar, pero no currying. Aquí hay una cita de una publicación de blog sobre la diferencia :
Donde la aplicación parcial toma una función y a partir de ella construye una función que toma menos argumentos, currying funciones de compilación que toman múltiples argumentos por composición de funciones que cada uno toma un solo argumento.
Espero que ayude.
Es curry Javascript lo que estás buscando?
Puede usar Function.prototype.bind()
para esto. Es una adición de ES5.
Además del uso común de establecer el contexto de una función ( this
valor), también puede establecer argumentos parciales.
function out(a, b) {
document.write(a + " " + b);
}
function setter(func) {
return func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)));
}
setter(out, "hello")("world");
setter(out, "hello", "world")();
Mi función setter
es realmente muy simple. La parte más larga es simplemente obtener la lista de argumentos. Voy a dividir el código de esta manera:
func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1)))
func.bind.apply( ) // need to use apply to pass multiple arguments as an array to bind()
func, // apply needs a context to be run in
[window].concat( ) // pass an array of arguments to bind(), starting with window, to be the global context
[].slice.call(arguments).slice(1) // convert the arguments list to an array, and chop off the initial value
Es compatible con estos navegadores : Chrome 7+, Firefox 4+, IE9 +. MDN (vinculado al principio) tiene un polyfill sin embargo.
Si usas Dojo, simplemente llama a dojo.hitch () que hace casi exactamente lo que quieres. Casi, porque también se puede usar para empaquetar el contexto. Pero tu ejemplo es primero:
dojo.hitch(out, "hello")("world");
dojo.hitch(out, "hello", "world")();
Tanto como:
var A = {
sep: ", ",
out: function(a, b){ console.log(a + this.sep + b); }
};
// using functions in context
dojo.hitch(A, A.out, "hello")("world");
dojo.hitch(A, A.out, "hello", "world")();
// using names in context
dojo.hitch(A, "out", "hello")("world");
dojo.hitch(A, "out", "hello", "world")();
dojo.hitch () es la parte de Dojo Base, por lo que tan pronto como haya incluido dojo.js estará a su disposición.
Otro recurso general está disponible en el módulo dojox.lang.functional.curry (documentado en Funcionalidad en JavaScript con Dojo - solo busque "curry" en esta página). Específicamente, es posible que desee ver curry () y parcial ().
curry () acumula argumentos (como en su ejemplo) pero con una diferencia: tan pronto como se satisface el arity, llama a la función que devuelve el valor. Implementando tu ejemplo:
df.curry(out)("hello")("world");
df.curry(out)("hello", "world");
Observe que la última línea no tiene "()" al final; se llama automáticamente.
parcial () permite reemplazar argumentos al azar:
df.partial(out, df.arg, "world")("hello");
Usando JavaScript apply()
, puedes modificar el function prototype
la function prototype
Function.prototype.pass = function() {
var args = arguments,
func = this;
return function() {
func.apply(this, args);
}
};
A continuación, puede llamarlo como out.pass(''hello'',''world'')
apply
toma una matriz para 2nd argumento / parámetro.
arguments
es propiedad disponible dentro de la función que contiene todos los parámetros en la matriz como estructura.
Otra forma común de hacer esto es usar bind
loadedFunc = func.bind(this, v1, v2, v3);
entonces
loadedFunc() === this.func(v1,v2,v3);
esto es suficiente, aunque poco feo.
function myLog(arg1,arg2,arg3){
return function(){
//you can use the arguments from the parent scope
console.log(arg1+" "+arg2+" "+arg3);
};
}
var passMeAnywhere = myLog(1,2,3);
//execute the function, args will be in the immediate lexical scope.
passMeAnywhere();
//One of the previous posts showed a way for context binding
//Context binding allows any context
//New is not required with binding