Сохранить доступ к этой области

У меня есть цвет, сохраненный в атрибуте данных на моей кнопке, который я хотел использовать в переключателе. Однако, когда я пытался получить доступ к данным с помощью this, данных не было. Как я могу сохранить доступ к правильной области this?

Я пытался только переключить данный цвет для элементов, которые не содержат Skip.

HTML

<div>
 <input id="toggleButton" type="button" value="Toggle" data-color="Red" />
</div>
<div id="toggleSet">
<div>Element</div>
 <div>Skip</div>
 <div>Element</div>
</div>

CSS

.ActivateRed{ color: red; }

JS

$('#toggleButton').click(function(){
 $("#toggleSet div").each(function(index,element){
  if( element.innerHTML != "Skip" ){
   $(element).toggleClass("Activate"+$(this).data("color"));
                                       //^this has no data to access?
                                       //Why am I getting undefined?
  }
 });
});

Ниже приведена jsFiddle. Я продолжаю получать Activateundefined как имя класса. Почему нет this доступа к моим данным toggleButton?

Ответ 1

Объяснение проблемы

это изменилось

Значение this MDN изменилось и больше не ссылается на ожидаемый элемент или значение, Часто это происходит из-за того, что область действия изменилась, и, как результат, имеет ссылку this.

это содержится в контексте выполнения

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

контексты выполнения связывают это

Когда элемент управления входит в контекст выполнения (в этой области выполняется код), среда для переменных настраивается (Лексическая и переменная среды - по существу это создает область для ввода переменных, которые уже были доступны, и область для локальных переменные, которые необходимо сохранить), и происходит привязка this.

эта привязка была изменена для контекста выполнения

Эти контексты образуют логический стек. В результате контексты, более глубокие в стеке, имеют доступ к предыдущим переменным, но их привязки могут быть изменены. Каждый раз, когда jQuery вызывает функцию обратного вызова, он изменяет эту привязку, используя apply MDN.

callback.apply( obj[ i ] )//where obj[i] is the current element

Результатом вызова apply является то, что внутри функций обратного вызова jQuery this относится к текущему элементу, который используется функцией обратного вызова.

Например, в .each обычно используется функция обратного вызова .each(function(index,element){/*scope*/}). В этой области, this == element является истиной. Следствием этого является то, что если вы ожидали, что предыдущий this будет доступен, он будет привязан к другому элементу.

Краткое объяснение this в обратных вызовах jQuery

Как показано выше, обратные вызовы jQuery используют функцию apply для привязки вызываемой функции к текущему элементу. Этот элемент исходит из массива элементов объекта jQuery. Каждый построенный объект jQuery содержит массив элементов, которые соответствуют селектору jQuery API, который использовался для создания экземпляра jQuery объект.

$(selector) вызывает функцию jQuery (помните, что $ является ссылкой на jQuery, code: window.jQuery = window.$ = jQuery;). Внутренне функция jQuery создает объект функции. Поэтому, хотя это может быть не сразу очевидным, использование $() внутренне использует new jQuery(). Часть конструкции этого объекта jQuery состоит в том, чтобы найти все совпадения селектора. Затем объект jQuery содержит массив-подобную структуру элементов DOM, соответствующих селектору.

Когда вызывается функция api jQuery, она будет внутренне перебирать эту структуру, подобную массиву. Для каждого элемента массива он вызывает функцию обратного вызова для api, привязывая обратный вызов this к текущему элементу. Этот вызов можно увидеть в фрагменте кода выше, где obj - структура, подобная массиву, и i - это итератор, используемый для позиции в массиве текущего элемента.

Поиск решения

Трудно определить, что произошло, поскольку jQuery имеет тенденцию терпеть неудачу. .data() jQuery API по-прежнему является действительным вызовом здесь, он просто возвращает undefined. В результате вышеприведенный код создает имя класса "Активировать" + undefined, "Activateundefined".

Важная часть, которую следует признать здесь, заключается в том, что jQuery изменил привязку this. Чтобы использовать предыдущую привязку this, значение должно быть сохранено в переменной. Общее имя для хранения это that, self, me, или в лучшем случае фактическое описание того, что представляет this.

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

jsFiddle Demo

$('#toggleButton').click(function(){
 var toggleBtn = this;
     //^ store this into the toggleBtn variable
 $("#toggleSet div").each(function(index,element){
                           //^ binds `this` to the current element
  if( element.innerHTML != "Skip" ){
       //^ we could have used `this.innerHTML` here
     $(element).toggleClass("Activate"+$(toggleBtn).data("color"));
                                        //^ re-use the stored `this` value
  }
 });
});