Comment passer du contexte dans setTimeout
? Je souhaite appeler this.tip.destroy()
si this.options.destroyOnHide
après 1000 ms. Comment puis je faire ça?
if (this.options.destroyOnHide) {
setTimeout(function() { this.tip.destroy() }, 1000);
}
Lorsque j'essaie ce qui précède, this
fait référence à la fenêtre.
EDIT: En résumé, lorsque l’on a posé cette question à 2010, le moyen le plus courant de résoudre ce problème était de sauvegarder une référence au contexte dans lequel setTimeout
L'appel à la fonction est effectué, car setTimeout
exécute la fonction avec this
pointant vers l'objet global:
var that = this;
if (this.options.destroyOnHide) {
setTimeout(function(){ that.tip.destroy() }, 1000);
}
Dans la spécification ES5, publiée juste un an avant cette date, elle introduisait la méthode bind
, cela n'était pas suggéré dans la réponse d'origine car elle n'était pas encore largement prise en charge et qu'il vous fallait plusieurs remplissages pour l'utiliser. mais maintenant c'est partout:
if (this.options.destroyOnHide) {
setTimeout(function(){ this.tip.destroy() }.bind(this), 1000);
}
La fonction bind
crée une nouvelle fonction avec la valeur this
préremplie.
Maintenant, dans JS moderne, c’est exactement le problème que les fonctions de flèche résolvent en ES6 :
if (this.options.destroyOnHide) {
setTimeout(() => { this.tip.destroy() }, 1000);
}
Les fonctions fléchées ne possèdent pas de valeur this
. Lorsque vous y accédez, vous accédez à la valeur this
de la portée lexicale englobante.
HTML5 aussi minuteries normalisées en 2011, et vous pouvez maintenant passer des arguments à la fonction de rappel:
if (this.options.destroyOnHide) {
setTimeout(function(that){ that.tip.destroy() }, 1000, this);
}
Voir également:
Il existe des raccourcis prêts à l'emploi (sucre syntaxique) pour la fonction wrapper @CMS avec laquelle on répond. (Ci-dessous, en supposant que le contexte souhaité est _this.tip
_.)
Si vous ciblez navigateur compatible avec ECMA-262, 5ème édition (ECMAScript 5) ou Node.js , vous pouvez utiliser Function.prototype.bind
. Vous pouvez éventuellement passer n'importe quel argument de fonction pour créer fonctions partielles .
_fun.bind(thisArg[, arg1[, arg2[, ...]]])
_
Encore une fois, dans votre cas, essayez ceci:
_if (this.options.destroyOnHide) {
setTimeout(this.tip.destroy.bind(this.tip), 1000);
}
_
La même fonctionnalité a également été implémentée dans Prototype (toute autre bibliothèque?).
_Function.prototype.bind
_ peut être implémenté comme ceci si vous voulez une compatibilité ascendante personnalisée (mais veuillez respecter les notes).
Pour un développement à la pointe de la technologie (2015), vous pouvez utiliser les grandes fonctions de flèche , qui sont élément de la spécification ECMAScript 2015 (Harmony/ES6/ES2015) ( exemples ).
Une expression de fonction de flèche (également appelée fonction de flèche épaisse ) a une syntaxe plus courte que celle des expressions de fonction et lie lexicalement la valeur
this
[...].
_(param1, param2, ...rest) => { statements }
_
Dans votre cas, essayez ceci:
_if (this.options.destroyOnHide) {
setTimeout(() => { this.tip.destroy(); }, 1000);
}
_
Si vous utilisez déjà jQuery 1.4+, il existe une fonction toute prête pour définir explicitement le contexte this
d'une fonction.
jQuery.proxy () : Prend une fonction et en retourne une nouvelle qui aura toujours un contexte particulier.
_$.proxy(function, context[, additionalArguments])
_
Dans votre cas, essayez ceci:
_if (this.options.destroyOnHide) {
setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}
_
Il est disponible dans Underscore.js, ainsi que lodash, ainsi que _.bind(...)
1 , 2
bind Lier une fonction à un objet, ce qui signifie que chaque fois que la fonction est appelée, la valeur de
this
sera être l'objet. Vous pouvez également associer des arguments à la fonction pour les pré-remplir, également appelée application partielle.
__.bind(function, object, [*arguments])
_
Dans votre cas, essayez ceci:
_if (this.options.destroyOnHide) {
setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}
_
Dans les navigateurs autres qu'Internet Explorer, vous pouvez transmettre les paramètres à la fonction ensemble après le délai:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
Donc, vous pouvez faire ceci:
var timeoutID = window.setTimeout(function (self) {
console.log(self);
}, 500, this);
C’est mieux en termes de performances qu’une recherche d’étendue (mise en cache de this
dans une variable en dehors de l’expression de délai d’intervalle/intervalle), puis création d’une fermeture (en utilisant $.proxy
ou Function.prototype.bind
) .
Le code pour le faire fonctionner dans les IE de Webreflection :
/*@cc_on
(function (modifierFn) {
// you have to invoke it as `window`'s property so, `window.setTimeout`
window.setTimeout = modifierFn(window.setTimeout);
window.setInterval = modifierFn(window.setInterval);
})(function (originalTimerFn) {
return function (callback, timeout){
var args = [].slice.call(arguments, 2);
return originalTimerFn(function () {
callback.apply(this, args)
}, timeout);
}
});
@*/
NOTE: Cela ne fonctionnera pas dans IE
var ob = {
p: "ob.p"
}
var p = "window.p";
setTimeout(function(){
console.log(this.p); // will print "window.p"
},1000);
setTimeout(function(){
console.log(this.p); // will print "ob.p"
}.bind(ob),1000);
Si vous utilisez underscore
, vous pouvez utiliser bind
.
Par exemple.
if (this.options.destroyOnHide) {
setTimeout(_.bind(this.tip.destroy, this), 1000);
}