2016-11-21 3 views
2

У меня есть этот тактовый объект:обратного вызова с `this` путаницей

var Clock = { 
    start: function() { 
     $('#btnScrollPause').show(); 
     $('#btnScrollResume').hide(); 

     advance(); 
     this.interval = setInterval(function() { 
     advance(); 
     }, 5000); 
    }, 

    pause: function() { 
     $('#btnScrollPause').hide(); 
     $('#btnScrollResume').show(); 
     this.reset(); 
    }, 

    resume: function() { 
     if (!this.interval) { 
     this.start(); 
     } 
    }, 

    reset: function() { 
     clearInterval(this.interval); 
     delete this.interval; 
    } 
    }; 

У меня есть две кнопки, приостанавливать и возобновлять автоматическую прокрутку элемента, но моя путаница на обработчиках кликов, которые я прикрепленные к их.

Если я вызываю функцию паузы, как это:

// 1 
$('#btnScrollPause').click(function() { 
    Clock.pause(); 
}); 

Он работает правильно, но если я пытаюсь сократить код следующим образом:

// 2 
$('#btnScrollPause').click(Clock.pause); 

Он больше не работает, и я получаю error "this.reset не определен". Кроме того, если я сделаю функцию и использую ее в обработчике кликов, то:

// 3 
$('#btnScrollPause').click(scrollPause); 

function scrollPause() { 
    Clock.pause(); 
} 

Это работает! Может кто-нибудь объяснить, почему 1 и 3 работают, но 2 нет?

+3

Пример-2. Внутри вашей функции 'pause' это' означает '# btnScrollPause', а не ваш объект' Clock'. Так как '# btnScrollPause' не имеет функции с именем' reset', вы получаете ошибку – bassxzero

+3

Два связанных (возможно, обмана?) Вопросов и ответов с большим количеством полезной информации по этой теме: [Как работает ключевое слово this?] (Http : //stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) и [Как получить доступ к правильному 'this'/context внутри обратного вызова?] (http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-in-a-callback) –

+0

Теперь кажется очевидным – JB06

ответ

2

связывание Объект this является летучим в JavaScript ... то есть, это не всегда указывают на один и тот же объект, и его привязка может меняться от одной строки кода до самой следующей. Как вы вызываете код, который содержит слово this, определяет, к какому объекту он будет привязан.

Если бы вы сделали экземпляр Clock (т.е. var c = new Clock()), а затем сказал:

$('#btnScrollPause').click(c.pause); 

Он работал бы потому, что this будет привязан к экземпляру Clock ссылается переменная c.

Но, поскольку он стоит с вашим кодом, this привязан к вашей кнопке, потому что это объект, который инициировал код.

Вот контрольный список, из которого вы можете следить, что this свяжется с ...

Если код, который содержит this вызывается:

  1. В качестве метода или свойства экземпляра объекта (через переменную экземпляра):

    var o = new Object(); 
    
    // "this" will be bound to the "o" object instance 
    // while "someProperty" and "someMethod" code executes 
    o.someProperty = someValue; 
    o.someMethod(); 
    
  2. Через .call(), .apply(), .bind() или Array.prototype.fn обращение:

    // "this" will be bound to the object suppled as the "thisObjectBinding" 
    someFunction.call(thisObjectBinding, arg, arg); 
    someFunction.apply(thisObjectBinding, [arg, arg]); 
    var newFunc = someFunction.bind(thisObjectBinding, arg, arg); 
    

    Кроме того, некоторые Array.prototype методы позволяют для thisObject быть принят, который будет изменять привязку для продолжительности вызова метода:

    Array.prototype.every(callbackfn [ , thisArg ]) 
    Array.prototype.some(callbackfn [ , thisArg ]) 
    Array.prototype.forEach(callbackfn [ , thisArg ]) 
    Array.prototype.map(callbackfn [ , thisArg ]) 
    Array.prototype.filter(callbackfn [ , thisArg ]) 
    
  3. Если ни один из других сценариев не применяются, по умолчанию связывание происходит.

    3a. При действии "use strict":

    3b. Без "use strict" в действие: this связывается с глобальным объектом

** Примечание: this связывания также могут быть затронуты при использовании eval(), но в качестве общего передового опыта, использование eval() следует избегать.

+0

Кажется, что я всегда должен создавать переменную для любого объекта, который я создаю, который использует ключевое слово this this быть в безопасности, правильно? – JB06

+0

@ JB06 Вы можете сделать это ... и сначала это немного упростит. Но функция '.bind()' очень мощная и позволяет существенно переопределить * this'. Этот параметр очень полезен, когда вы начинаете создавать более динамичный код. Это также верно в методах «Array.prototype», о которых я упомянул выше. Я думаю, что привыкание (и обнимание) нестатической привязки «это» является ключевым. Кстати, '.call()' и '.apply()' больше не рекомендуется, так как '.bind()' эффективно заменяет их. –

4

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

Один из вариантов, что у вас есть использует .bind функцию:

$('#btnScrollPause').click(Clock.pause.bind(Clock)); 

Смежный вопрос: How does the “this” keyword work?

Смежные вопросы