Transmettre le contexte correct "ceci" à setTimeout callback? [dupliquer]
cette question a déjà une réponse ici:
Comment passer le contexte dans setTimeout
? Je veux appeler this.tip.destroy()
si this.options.destroyOnHide
après 1000 ms. Comment je peux faire ça?
if (this.options.destroyOnHide) {
setTimeout(function() { this.tip.destroy() }, 1000);
}
quand j'essaie ce qui précède, this
se réfère à la fenêtre.
5 réponses
vous devez sauvegarder une référence au contexte dans lequel l'appel de fonction setTimeout
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);
}
vous pouvez facilement prouver que setTimeout
mettre this
à l'objet global par:
(function () {
alert(this); // alerts hello
setTimeout(function(){
alert(this == window); // true
}, 1000);
}).call("hello");
voir aussi:
il y a des raccourcis tout faits (sucre syntaxique) à la fonction wrapper @CMS auxquels on répond. (Ci-dessous en supposant que le contexte est this.tip
.)
ECMAScript 5 ( les navigateurs actuels , Nœud.js) et le Prototype.js
si vous ciblez navigateur compatible avec ECMA-262, 5e édition (ECMAScript 5) ou noeud.js , vous pourriez utiliser Function.prototype.bind
. Vous pouvez éventuellement passer tous les arguments de fonction pour créer partial functions .
fun.bind(thisArg[, arg1[, arg2[, ...]]])
encore, 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 le Prototype (d'autres bibliothèques?).
Function.prototype.bind
peut être mis en œuvre comme ceci si vous voulez une rétrocompatibilité personnalisée (mais veuillez respecter les notes).
ECMAScript 2015 ( certains navigateurs , noeud.js 5.0.0+)
de pointe Pour le développement (2015), vous pouvez utiliser fat flèche fonctions , qui sont une partie de l'ECMAScript 2015 (Harmonie/ES6/ES2015) spécification ( exemples ).
An arrow function expression (également connu sous le nom fat arrow function ) a une syntaxe plus courte que les 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);
}
jQuery
si vous utilisez déjà jQuery 1.4+, il y a une fonction prête à l'emploi pour définir explicitement le contexte this
d'une fonction.
jQuery.proxy() : Prend une fonction et renvoie un nouveau 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);
}
trait de Soulignement.js , lodash
c'est disponible en Underscore.js, ainsi que lodash, as _.bind(...)
1 , 2
bind lient une fonction à un objet, ce qui signifie que chaque fois que la fonction est appelée, la valeur de
this
sera objet. Optionnellement, liez les arguments à la fonction pour les pré-remplir, aussi connu sous le nom d'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 passer 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 performance qu'une recherche de scope (mise en cache this
dans une variable en dehors de l'expression timeout / interval), puis la création d'une fermeture (en utilisant $.proxy
ou Function.prototype.bind
).
Le code pour le faire fonctionner dans IEs from 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);
}
});
@*/
si vous utilisez underscore
, vous pouvez utiliser bind
.
E. G.
if (this.options.destroyOnHide) {
setTimeout(_.bind(this.tip.destroy, this), 1000);
}
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);