Come associare gli argomenti della funzione senza vincolare questo?

In Javascript, come posso associare argomenti a una funzione senza vincolare this parametro?

Per esempio:

 //Example function. var c = function(a, b, c, callback) {}; //Bind values 1, 2, and 3 to a, b, and c, leave callback unbound. var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope? 

Come posso evitare l’effetto collaterale di dover associare l’ambito della funzione (ad es. Impostare this = null)?

Modificare:

Dispiace per la confusione. Voglio associare gli argomenti, quindi essere in grado di chiamare la funzione associata in seguito e farlo funzionare esattamente come se avessi chiamato la funzione originale e gli avessi passato gli argomenti associati:

 var x = 'outside object'; var obj = { x: 'inside object', c: function(a, b, c, callback) { console.log(this.x); } }; var b = obj.c.bind(null, 1, 2, 3); //These should both have exact same output. obj.c(1, 2, 3, function(){}); b(function(){}); //The following works, but I was hoping there was a better way: var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice? 

Sono ancora nuovo a questo, mi dispiace per la confusione.

Grazie!

Puoi farlo, ma è meglio evitare di pensarlo come “vincolante” poiché questo è il termine usato per impostare il valore “questo”. Forse pensarlo come “avvolgere” gli argomenti in una funzione?

Quello che fai è creare una funzione con gli argomenti desiderati incorporati tramite le chiusure:

 var withWrappedArguments = function(arg1, arg2) { return function() { ... do your stuff with arg1 and arg2 ... }; }(actualArg1Value, actualArg2Value); 

Spero di avere la syntax proprio lì. Quello che fa è creare una funzione chiamata withWrappedArguments () (essere pedante è una funzione anonima assegnata alla variabile) che puoi chiamare in qualsiasi momento dove e agirà sempre con actualArg1Value e actualArg2Value, e qualsiasi altra cosa tu voglia inserire Là. Puoi anche farlo accettare ulteriori argomenti al momento della chiamata, se lo desideri. Il segreto è tra parentesi dopo la parentesi finale di chiusura. Questi fanno sì che la funzione esterna venga immediatamente eseguita, con i valori passati, e per generare la funzione interna che può essere chiamata più tardi. I valori passati vengono quindi congelati al momento della generazione della funzione.

Questo è effettivamente ciò che fa il binding, ma in questo modo è esplicito che gli argomenti avvolti sono semplicemente chiusure su variabili locali e non è necessario cambiarne il comportamento.

Nel metodo bind nativo , this valore nella funzione risultato viene perso. Tuttavia, puoi facilmente ricodificare lo shim comune per non utilizzare un argomento per il contesto:

 Function.prototype.arg = function() { if (typeof this !== "function") throw new TypeError("Function.prototype.arg needs to be called on a function"); var slice = Array.prototype.slice, args = slice.call(arguments), fn = this, partial = function() { return fn.apply(this, args.concat(slice.call(arguments))); // ^^^^ }; partial.prototype = Object.create(this.prototype); return partial; }; 

In ES6, questo è fatto facilmente usando i parametri di rest in congiunzione con l’ operatore di spread .

Quindi possiamo definire una funzione bindArgs che funziona come bind , con la bindArgs che solo gli argomenti sono vincolati, ma non il contesto ( this ).

 Function.prototype.bindArgs = function (...boundArgs) { const targetFunction = this; return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); }; }; 

Quindi, per una funzione specificata foo e un object obj , la dichiarazione

 return foo.call(obj, 1, 2, 3, 4); 

è equivalente a

 let bar = foo.bindArgs(1, 2); return bar.call(obj, 3, 4); 

dove solo il primo e il secondo argomento sono vincolati a bar , mentre il contesto object specificato nell’invocazione viene usato e gli argomenti extra vengono aggiunti dopo gli argomenti associati. Il valore di ritorno viene semplicemente inoltrato.

Un’implementazione ancora più piccola solo per divertimento:

 function bindWithoutThis(cb) { var bindArgs = Array.prototype.slice.call(arguments, 1); return function () { var internalArgs = Array.prototype.slice.call(arguments, 0); var args = Array.prototype.concat(bindArgs, internalArgs); return cb.apply(this, args); }; } 

Come usare:

 function onWriteEnd(evt) {} var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data"); 
 var b = function() { return c(1,2,3); }; 

È un po ‘difficile dire esattamente cosa vuoi fare in definitiva perché l’esempio è un po’ arbitrario, ma potresti voler esaminare i partial (o currying): http://jsbin.com/ifoqoj/1/edit

 Function.prototype.partial = function(){ var fn = this, args = Array.prototype.slice.call(arguments); return function(){ var arg = 0; for ( var i = 0; i < args.length && arg < arguments.length; i++ ) if ( args[i] === undefined ) args[i] = arguments[arg++]; return fn.apply(this, args); }; }; var c = function(a, b, c, callback) { console.log( a, b, c, callback ) }; var b = c.partial(1, 2, 3, undefined); b(function(){}) 

Link all'articolo di John Resig: http://ejohn.org/blog/partial-functions-in-javascript/

Usa un protagonist !

 var geoOpts = {...}; function geoSuccess(user){ // protagonizes for 'user' return function Success(pos){ if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); } var data = {pos.coords: pos.coords, ...}; // now we have a callback we can turn into an object. implementation can use 'this' inside callback if(user){ user.prototype = data; user.prototype.watch = watchUser; thus.User = (new user(data)); console.log('thus.User', thus, thus.User); } } } function geoError(errorCallback){ // protagonizes for 'errorCallback' return function(err){ console.log('@DECLINED', err); errorCallback && errorCallback(err); } } function getUserPos(user, error, opts){ nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts); } 

Fondamentalmente, la funzione che vuoi passare ai parametri diventa un proxy che puoi chiamare per passare una variabile, e restituisce la funzione che vuoi effettivamente fare.

Spero che questo ti aiuti!

Un utente anonimo ha pubblicato queste informazioni aggiuntive:

Basandosi su ciò che è già stato fornito in questo post, la soluzione più elegante che ho visto è quella di Curry i tuoi argomenti e il contesto:

 function Class(a, b, c, d){ console.log('@Class #this', this, a, b, c, d); } function Context(name){ console.log('@Context', this, name); this.name = name; } var context1 = new Context('One'); var context2 = new Context('Two'); function curryArguments(fn) { var args = Array.prototype.slice.call(arguments, 1); return function bindContext() { var additional = Array.prototype.slice.call(arguments, 0); return fn.apply(this, args.concat(additional)); }; } var bindContext = curryArguments(Class, 'A', 'B'); bindContext.apply(context1, ['C', 'D']); bindContext.apply(context2, ['Y', 'Z']); 

Bene per l’esempio che hai dato, questo lo farà

 var b= function(callback){ return obj.c(1,2,3, callback); }; 

Se si desidera garantire la chiusura dei parametri:

 var b= (function(p1,p2,p3, obj){ var c=obj.c; return function(callback){ return c.call(obj,p1,p2,p3, callback); } })(1,2,3,obj) 

Ma se è così, dovresti limitarti alla tua soluzione:

 var b = obj.c.bind(obj, 1, 2, 3); 

È il modo migliore

Semplice come quello?

 var b = (cb) => obj.c(1,2,3, cb) b(function(){}) // insidde object 

Soluzione più generale:

 function original(a, b, c) { console.log(a, b, c) } let tied = (...args) => original(1, 2, ...args) original(1,2,3) // 1 2 3 tied(5,6,7) // 1 2 5 

Perché non utilizzare un wrapper attorno alla funzione per salvare questo come mythis?

 function mythis() { this.name = "mythis"; mythis = this; function c(a, b) { this.name = "original"; alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name); return "ok"; } return { c: c } }; var retval = mythis().c(0, 1); 

Usando LoDash puoi usare la funzione _.partial .

 const f = function (a, b, c, callback) {} const pf = _.partial(f, 1, 2, 3) // f has first 3 arguments bound. pf(function () {}) // callback. 

jQuery 1.9 ha portato esattamente quella caratteristica con la funzione proxy.

A partire da jQuery 1.9, quando il contesto è nullo o indefinito, la funzione proxy verrà chiamata con lo stesso object con cui è stato chiamato il proxy. Ciò consente a $ .proxy () di essere utilizzato per applicare parzialmente gli argomenti di una funzione senza modificare il contesto.

Esempio:

 $.proxy(this.myFunction, undefined /* leaving the context empty */, [precededArg1, precededArg2]); 

Potresti voler associare il riferimento a questo in ultimo, ma il tuo codice: –

 var c = function(a, b, c, callback) {}; var b = c.bind(null, 1, 2, 3); 

Ad esempio, per l’associazione già applicata, non è ansible modificarla. Quello che suggerirò che uso riferimento anche come un parametro come questo: –

 var c = function(a, b, c, callback, ref) { var self = this ? this : ref; // Now you can use self just like this in your code }; var b = c.bind(null, 1, 2, 3), newRef = this, // or ref whatever you want to apply inside function c() d = c.bind(callback, newRef); 

Caso d’uso Jquery:

anziché:

 for(var i = 0;i<3;i++){ $('').appendTo('body').click(function(i){ $(this).val(i); // wont work, because 'this' becomes 'i' }.bind(i)); } 

Usa questo:

 for(var i = 0;i<3;i++){ $('').appendTo('body').click(function(e){ var i = this; $(e.originalEvent.target).val(i); }.bind(i)); }