2014-12-30 13 views
30

Scusa se mi manca qualcosa di ovvio, ma non riesco a capire come associare un argomento specifico (ennesimo) di una funzione in javascript. La maggior parte della mia programmazione funzionale che ho imparato è stata di Scala, quindi non sono sicuro che ciò sia possibile anche in JS.Funzione JavaScript parzialmente applicata - Come associare solo il 2 ° parametro?

Per esempio, ho capito che posso fare il seguito di impegnare la prima argomentazione

var add = function (a, b) { 
    return a + b; 
}; 

add(1, 3); //returns 4 

var addThree = add.bind(null, 3); //this = null. a = 3 
addThree(4);      //returns 7 

ma come posso legare il secondo argomento e lasciare il primo come è. In altre parole, come posso legare solo a "b"?

Da quello che posso dire da mozilla - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind, gli argomenti sono effettivamente nidificati che fanno sembrare che deve essere in ordine specifico? (Molto probabilmente sto leggendo questo sbagliato)

Modifica: Mi rendo conto che questa è una sorta di esempio forzato. Sto solo cercando di imparare nel caso in cui alla fine mi occupi di qualcosa di più complesso dell'aggiunta di 2 numeri. Sto anche cercando di capire come gli argomenti bind() stiano effettivamente lavorando sotto il cofano.

+0

Sicuro che non intendi "add.bind (null, 3)'? 'add.apply()' viene eseguito immediatamente con gli argomenti e fornito 'this' – deitch

+0

sì, sì, significavo vincolare. appena aggiornato, grazie :) –

+6

Non è inserito nella lingua, ma controlla questo articolo http://ejohn.org/blog/partial-functions-in-javascript/ dove mostra un modo per farlo specificando 'indefinito' per i parametri che vuoi compilare in seguito. –

risposta

23

Certo che puoi farlo. Ecco una soluzione ES6 utilizzando l'operatore di spread (...), poiché è un po 'più compatto.

// Bind arguments starting after however many are passed in. 
function bind_trailing_args(fn, ...bound_args) { 
    return function(...args) { 
     return fn(...args, ...bound_args); 
    }; 
} 

Se preferite per specificare la posizione in cui inizia la rilegatura:

// Bind arguments starting with argument number "n". 
function bind_args_from_n(fn, n, ...bound_args) { 
    return function(...args) { 
     return fn(...args.slice(0, n-1), ...bound_args); 
    }; 
} 

IN ES5, si deve impazzire con la costruzione di liste di argomenti.

// ES5 version: construct arguments lists yourself 
function bind_trailing_args(fn) { 
    var bound_args = [].slice.call(arguments, 1); 
    return function() { 
     var args = [].concat.call(arguments, bound_args); 
     return fn.apply(this, args); 
    }; 
} 

A differenza dei primi due esempi, questo gestisce this correttamente.

Nel contesto del vostro esempio:

var addThree = bind_trailing_args(add, 3); 
addThree(1) // calls add(1, 3) 

Si potrebbe anche considerare l'utilizzo di una delle librerie di programmazione funzionali disponibili per JS, come http://osteele.com/sources/javascript/functional/. La cosa che vuoi è chiamata rcurry lì.

+0

Grande risposta che illustra la potenza di es-6! – Hrishi

+0

Questo è interessante. Dovrò giocarci quando ecmascript 6 funzionerà nella mia console. Sono curioso di sapere quali sono le implicazioni su "this" sta usando i primi 2 metodi. Sai se "questo" perde spazio a causa della chiusura? Ho pensato semanticamente che questo aspetto è diverso poiché obj.bind() prende l'oggetto vincolante come prima cosa. –

+0

Quindi con ES6 non esiste un modo semplice per associare un sottoinsieme arbitrario di argomenti che non è, ad esempio, che non inizia né termina la lista degli argomenti? – matanster

6

Bene. Lo butterò lì fuori.

var add = function(a,b) { 
    return a + b; 
}; 

var addThree = function(a) { 
    return add(a,3); 
}; 

add(1,2); 
addThree(4); 

Forse andrà bene per alcuni.

+0

Questo era il mio pensiero iniziale, ma speravo che l'applicazione parziale fosse parte del linguaggio principale stesso. Posso chiedere quale sia lo scopo di assegnare la funzione a un oggetto higherOrder? Non possiamo fare lo stesso senza creare un nuovo oggetto per questo? –

+0

@JustinMaat Capisco che questo non era esattamente quello che stavi chiedendo, ma ha risolto il problema in un modo diverso. Sono abituato a non posizionare le cose in uno spazio globale. Lo cambierò per questa domanda. – Ben

+0

Ok, sì, hai ragione, quanto sopra sarebbe nello spazio globale. In genere avvolgo anche il mio codice, è stato semplicemente confuso da quanto sopra sembrava implicare che l'oggetto wrapper fosse necessario per decorare la funzione. Ad ogni modo, ti darò un upvote in quanto questa è un'alternativa. –

22

È possibile utilizzare lodash di _.bind per raggiungere questo obiettivo:

var add = function(a, b) { 
 
    document.write(a + b); 
 
}; 
 

 
// Bind to first parameter (Nothing special here) 
 
var bound = _.bind(add, null, 3); 
 
bound(4); 
 
// → 7 
 

 
// Bind to second parameter by skipping the first one with "_" 
 
var bound = _.bind(add, null, _, 4); 
 
bound(3); 
 
// → 7
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.9.3/lodash.min.js"></script>

Io sono di solito le librerie e preferiscono codifica le mie funzioni di utilità, ma un'eccezione può essere fatto facilmente per lodash. Ti consiglio caldamente di controllare its documentation ogni volta che hai un "Questo deve essere nella lingua da qualche parte!" momento. Riempie molti spazi in JavaScript.

0

si può provare questo:

Function.prototype.bindThemAll = function bindThemAll(thisArg, ...boundArgs) 
 
    (boundArgs.fn = this, function(...args) boundArgs.fn.call(thisArg || this, ...boundArgs.map((el) => el || args.shift()), ...args)); 
 

 
function fn() console.log("fn:", arguments.callee, "this:", this, "args:", arguments) 
 

 
var x = {a: 5}; 
 

 
var bfn = fn.bindThemAll(x, null, 2) 
 
bfn(1,3) 
 
x.bfn = fn.bindThemAll(null, null, 2) 
 
x.bfn(1,3)

argomenti legati con null o undefined verranno sostituiti con gli argomenti della funzione in ordine, gli argomenti rimanenti saranno aggiunti alla fine. verrà utilizzato un oggetto se è impegnato altrimenti la corrente verrà utilizzata ...

vedere la console per i risultati!

Problemi correlati