Comment passer le contexte this à une fonction?

213

Je pensais que ce serait quelque chose que je pourrais facilement google, mais peut-être que je ne pose pas la bonne question ...

Comment puis-je définir ce que "ceci" fait référence dans une fonction javascript donnée?

par exemple, comme avec la plupart des fonctions de jQuery telles que:

$(selector).each(function() {
   //$(this) gives me access to whatever selector we're on
});

Comment puis-je écrire / appeler mes propres fonctions autonomes qui ont une référence "this" appropriée lorsqu'elles sont appelées? J'utilise jQuery, donc s'il y a une manière spécifique à jQuery de le faire, ce serait idéal.

user126715
la source
Duplicata possible: stackoverflow.com/questions/520019/…
user123444555621
Je sais que c'est une vieille question, mais pour d'autres qui atterrissent ici, voir jQuery$.proxy
RyBolt

Réponses:

303

Les javascripts .call()et les .apply()méthodes vous permettent de définir le contexte d'une fonction.

var myfunc = function(){
    alert(this.name);
};

var obj_a = {
    name:  "FOO"
};

var obj_b = {
    name:  "BAR!!"
};

Vous pouvez maintenant appeler:

myfunc.call(obj_a);

Ce qui alerterait FOO. Dans l'autre sens, le passage obj_balerterait BAR!!. La différence entre .call()et .apply()est que .call()prend une liste séparée par des virgules si vous passez des arguments à votre fonction et avez .apply()besoin d'un tableau.

myfunc.call(obj_a, 1, 2, 3);
myfunc.apply(obj_a, [1, 2, 3]);

Par conséquent, vous pouvez facilement écrire une fonction hooken utilisant la apply()méthode. Par exemple, nous voulons ajouter une fonctionnalité à la .css()méthode jQuerys . Nous pouvons stocker la référence de fonction d'origine, écraser la fonction avec un code personnalisé et appeler la fonction stockée.

var _css = $.fn.css;
$.fn.css = function(){
   alert('hooked!');
   _css.apply(this, arguments);
};

Puisque l' argumentsobjet magique est un objet semblable à un tableau, nous pouvons simplement le passer à apply(). De cette façon, nous garantissons que tous les paramètres sont transmis à la fonction d'origine.

jAndy
la source
4
Juste une friandise amusante: si vous devez appeler la fonction à plusieurs reprises en référence à obj_a, par exemple, vous pouvez en créer une copie var boud_myfunc = myfunc.bind(obj_a)et l'appeler simplement bound_myfunc()si nécessaire.
wbadart
45

Utilisationfunction.call :

var f = function () { console.log(this); }
f.call(that, arg1, arg2, etc);

Où se thattrouve l'objet que vous voulez thisdans la fonction.

palswim
la source
1
functionest un mot-clé réservé; pensez à mettre à jour votre réponse pour inclure une fonction nommée car il function.call(...)n'est pas valide de JavaScript.
Daniel Allen
1
@DanielAllen: Sans la définition de l'exemple de nom de fonction que je fournirais, le code générera toujours une erreur JS. Mais, j'ai mis à jour l'exemple de nom de fonction.
palswim
16

jQuery utilise une .call(...)méthode pour affecter le nœud actuel à l' thisintérieur de la fonction que vous passez en tant que paramètre.

ÉDITER:

N'ayez pas peur de regarder à l'intérieur du code de jQuery lorsque vous avez un doute, tout est en Javascript clair et bien documenté.

c'est-à-dire: la réponse à cette question est autour de la ligne 574,
callback.call( object[ name ], name, object[ name ] ) === false

Micro
la source
12

Vous pouvez utiliser la fonction de liaison pour définir le contexte thisau sein d'une fonction.

function myFunc() {
  console.log(this.str)
}
const myContext = {str: "my context"}
const boundFunc = myFunc.bind(myContext);
boundFunc(); // "my context"
Scott Jungwirth
la source
12

Un autre exemple de base:

Ca ne fonctionne pas:

var img = new Image;
img.onload = function() {
   this.myGlobalFunction(img);
};
img.src = reader.result;

Travail:

var img = new Image;
img.onload = function() {
   this.myGlobalFunction(img);
}.bind(this);
img.src = reader.result;

Donc, fondamentalement: ajoutez simplement .bind (this) à votre fonction

Joery
la source
Cela devrait être la réponse acceptée. Syntaxe beaucoup plus facile, beaucoup plus facile à l'esprit ... bon travail Joery
nenea