metodo - prototype javascript
¿Usar Function.prototype.bind con una matriz de argumentos? (10)
¿Por qué no simplemente enlazar a la matriz de argumentos según su ejemplo y hacer que la función bound()
trate así como una matriz ?
Según el aspecto de su uso, está pasando una función como argumento final a bound()
, lo que significa que al pasar la matriz de argumentos real, evita tener que separar los argumentos de las devoluciones dentro de bound()
, lo que hace que sea más fácil jugar con.
¿Cómo puedo llamar a Function.prototype.bind con una matriz de argumentos, a diferencia de los argumentos codificados? (No usa ECMA6, por lo que no hay operador de propagación).
Estoy tratando de poner un envoltorio de promesas alrededor de un módulo que usa devoluciones de llamada y quiero vincular todos los argumentos pasados a mi método de envoltura y vincularlos. Luego deseo llamar a la función enlazada parcialmente aplicada con mi propia devolución de llamada, que resolverá o rechazará una promesa.
var find = function() {
var deferred, bound;
deferred = Q.defer();
bound = db.find.bind(null, arguments);
bound(function(err, docs) {
if(err) {
deferred.fail(err);
} else {
deferred.resolve(docs);
}
});
return deferred.promise;
}
Pero, obviamente, esto no funciona porque bind espera argumentos en lugar de una matriz de argumentos. Sé que podría hacer esto insertando mi devolución de llamada al final de la matriz de argumentos y usando apply:
arguments[arguments.length] = function(err, docs) { ... }
db.find.apply(null, arguments);
O al iterar sobre la matriz de argumentos y volver a vincular la función para cada argumento:
var bound, context;
for(var i = 0; i < arguments.length; i++) {
context = bound ? bound : db.find;
bound = context.bind(null, arguments[i]);
}
bound(function(err, docs) { ... })
Pero ambos métodos se sienten sucios. ¿Algunas ideas?
Acabo de tener una idea alternativa, aplicar parcialmente el valor null
para el contexto y luego usar apply
para llamar a la función parcialmente aplicada.
bound = db.find.bind.bind(null).apply(null, arguments);
Esto elimina la necesidad del aspecto ligeramente [null].concat()
en la respuesta de [null].concat()
.
El siguiente es un fragmento común de código que uso en todos mis proyectos:
var bind = Function.bind;
var call = Function.call;
var bindable = bind.bind(bind);
var callable = bindable(call);
La función bindable
ahora se puede usar para pasar una matriz para bind
siguiente manera:
var bound = bindable(db.find, db).apply(null, arguments);
De hecho, puede almacenar en caché bindable(db.find, db)
para acelerar el enlace de la siguiente manera:
var findable = bindable(db.find, db);
var bound = findable.apply(null, arguments);
Puede usar la función que se puede findable
con o sin una matriz de argumentos:
var bound = findable(1, 2, 3);
Espero que esto ayude.
Genéricamente, este esquema es suficiente:
//obj = db
//fnName = ''find''
var args = [this||null].concat(Array.prototype.slice.apply(arguments);
obj[fnName].bind.apply(obj[fnName], args);
La respuesta de Felix no funcionó para mí porque el objeto arguments
no es realmente una matriz (como señaló Otts). La solución para mí era simplemente cambiar bind
y apply
:
bound = db.find.apply.bind(db.find, null, arguments);
Me parece siguiente más limpio que las respuestas aceptadas
Function.bind.apply(db.find, [null].concat(arguments));
Para aquellos que usan ES6, Babel compila:
db.find.bind(this, ...arguments)
a:
db.find.bind.apply(db.find, [this].concat(Array.prototype.slice.call(arguments)));
Creo que es justo decir que Babel es bastante definitivo. Sin embargo, crédito a @ lorenz-lo-sauer, es casi idéntico.
Si alguien está buscando una muestra abstracta:
var binded = hello.apply.bind(hello,null,[''hello'',''world'']);
binded();
function hello(a,b){
console.log(this); //null
console.log(a); //hello
console.log(b); //world
}
Una respuesta definitiva y simple podría ser
Function.apply.bind(this.method, this, arguments);
Un poco "difícil" de entender, pero ordenado.
.bind
es una función normal, por lo que puede invocar .apply
.
Todo lo que tiene que hacer es pasar la función original como primer param y la deseada THIS
variable como primer elemento de la matriz de argumentos:
bound = db.find.bind.apply(db.find, [null].concat(arguments));
// ^-----^ ^-----^ THIS
Si eso se puede considerar más limpio o no se deja al lector.