Передать правильный" этот " контекст для обратного вызова setTimeout? [дубликат]


этот вопрос уже есть ответ здесь:

как передать контекст в setTimeout? Я хочу позвонить this.tip.destroy() Если this.options.destroyOnHide после 1000 мс. Как я могу это сделать?

if (this.options.destroyOnHide) {
     setTimeout(function() { this.tip.destroy() }, 1000);
} 

когда я пытаюсь выше, this относится к окну.

5 185

5 ответов:

вам нужно сохранить ссылку на контекст, где setTimeout вызов функции производится, потому что setTimeout выполняет функции this указывая на глобальный объект:

var that = this;
if (this.options.destroyOnHide) {
     setTimeout(function(){that.tip.destroy()}, 1000);
} 

вы можете легко доказать, что setTimeout set this к глобальному объекту по:

(function () {
  alert(this); // alerts hello
  setTimeout(function(){
    alert(this == window); // true
  }, 1000);
}).call("hello");

Читайте также:

есть готовые ярлыки (синтаксический сахар)для функции wrapper @CMS ответил С. (Ниже предполагается, что контекст, который вы хотите this.tip.)


ECMAScript 5 (современных браузеров узел.js) и прототип.js

если вы нацелены браузер совместим с ECMA-262, 5-е издание (ECMAScript 5) или узел.js, вы могли бы использовать Function.prototype.bind. Вы можете дополнительно передать любой аргументы функции для создания частичные функции.

fun.bind(thisArg[, arg1[, arg2[, ...]]])

еще раз, в вашем случае, попробуйте это:

if (this.options.destroyOnHide) {
    setTimeout(this.tip.destroy.bind(this.tip), 1000);
}

такая же функциональность также была реализовано в прототипе (любой другой библиотеки?).

Function.prototype.bind может быть реализовано следующим образом если вы хотите пользовательскую обратную совместимость (но, пожалуйста, соблюдайте Примечания).


ECMAScript 2015 (некоторые браузеры узел.js 5.0.0+)

для передовых разработок (2015) Вы можете использовать функции жирной стрелкой, которые часть спецификации ECMAScript 2015 (Harmony/ES6/ES2015) (примеры).

An выражение функции стрелой (также известный как функция жирной стрелки) имеет более короткий синтаксис по сравнению с функциональными выражениями и лексически связывает this значение.[ ..].

(param1, param2, ...rest) => { statements }

в вашем случае, попробуйте это:

if (this.options.destroyOnHide) {
    setTimeout(() => { this.tip.destroy(); }, 1000);
}

jQuery

если вы уже используете jQuery 1.4+, есть готовая функция для явной установки this контекст функции.

jQuery.прокси - (): принимает функцию и возвращает новую, которая всегда будет иметь определенный контекст.

$.proxy(function, context[, additionalArguments])

в вашем случае, попробуйте это:

if (this.options.destroyOnHide) {
    setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}

подчеркивания.js,лодашь

он доступен в подчеркивании.JS, а также лодашь, как _.bind(...)1,2

связать привязать функцию к объекту, это означает, что всякий раз, когда функция вызывается, значение this будет объект. Дополнительно можно привязать аргументы к функции для их предварительного заполнения, также известен как частичное применение.

_.bind(function, object, [*arguments])

в вашем случае, попробуйте это:

if (this.options.destroyOnHide) {
    setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}

bindjqueryподчеркивания.jsecmascript-5prototypejsузел.js

в браузерах, отличных от Internet Explorer, вы можете передавать параметры функции вместе после задержки:

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

Итак, вы можете сделать это:

var timeoutID = window.setTimeout(function (self) {
  console.log(self); 
}, 500, this);

это лучше с точки зрения производительности, чем поиск области (кэширование this в переменную вне выражения timeout / interval), а затем создание закрытия (с помощью $.proxy или Function.prototype.bind).

код, чтобы заставить его работать в IEs от 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);
    }
});
@*/

Если вы используете underscore, вы можете использовать bind.

например.

if (this.options.destroyOnHide) {
     setTimeout(_.bind(this.tip.destroy, this), 1000);
}

Примечание: это не будет работать в 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);