У меня есть следующий (довольно) простой фрагмент кода JavaScript, который я подключил к Greasemonkey. Он просматривает страницу, ищет теги <a>, href которых указывает на tinyurl.com, и добавляет атрибут «title», который определяет истинное место назначения ссылки. Большая часть важного кода происходит из более старого (неподдерживаемого) скрипта Greasemonkey, который прекращает работу, когда изменяется внутренний компонент, в котором хранится реализация XPath. Мой сценарий:
(function() {
var providers = new Array();
providers['tinyurl.com'] = function(link, fragment) {
// This is mostly taken from the (broken due to XPath component
// issues) tinyurl_popup_preview script.
link.title = "Loading...";
GM_xmlhttpRequest({
method: 'GET',
url: 'http://preview.tinyurl.com/' + fragment,
onload: function(res) {
var re = res.responseText.match("<blockquote><b>(.+)</b></blockquote>");
if (re)
{
link.title = re[1].replace(/\<br /\>/g, "").replace(/&/g, "&");
}
else
{
link.title = "Parsing failed...";
}
},
onerror: function() {
link.title = "Connection failed...";
}
});
};
var uriPattern = /(tinyurl\.com)/([a-zA-Z0-9]+)/;
var aTags = document.getElementsByTagName("a");
for (i = 0; i < aTags.length; i++)
{
var data = aTags[i].href.match(uriPattern);
if (data != null && data.length > 1 && data[2] != "preview")
{
var source = data[1];
var fragment = data[2];
var link = aTags[i];
aTags[i].addEventListener("mouseover", function() {
if (link.title == "")
{
(providers[source])(link, fragment);
}
}, false);
}
}
})();
(Причина, по которой ассоциативный массив "поставщиков" настроен таким образом, что я могу расширить его, чтобы охватить и другие службы сокращения URL-адресов.)
Я проверил, что все различные ветви кода достигаются правильно в тех случаях, когда проверяемая ссылка соответствует или не соответствует шаблону. То, что происходит не, - это любое изменение атрибута "title" тегов привязки. Я смотрел это через Firebug, бросал вызовы alert() слева и справа, и это просто никогда не меняется. В предыдущей итерации все выражения формы:
link.title = "...";
изначально был:
link.setAttribute("title", "...");
Это тоже не сработало. Я не новичок в JavaScript ИЛИ Greasemonkey, но этот меня поставил в тупик!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вместо этого попробуйте заменить корпус if этим кодом.
aTags[i].addEventListener("mouseover", (function(source, fragment)
{
return function()
{
if (this.title == "")
{
(providers[source])(this, fragment);
}
}
})(data[1], data[2]), false) ;
Обратите внимание, что после завершения цикла выполните aTags = null;.
Ваша проблема в том, что блок оператора if не является истинной областью действия, все, что var'd, будет принадлежать области внешней функции. Следовательно, ваша внутренняя функция, которую вы предоставляете в качестве обработчика событий, будет использовать источник, ссылку и фрагмент последнего прохода. Кроме того, поддерживая ссылки на объект DOM, вы получите утечку памяти из-за циклических ссылок.
Вышеупомянутый подход создает новую область видимости на каждом проходе через вызов функции, поэтому каждый источник и фрагмент находятся в своей собственной области. Он также использует тот факт, что функция, вызываемая как прослушиватель событий, имеет свойство this, указывающее на элемент, к которому она прикреплена, что позволяет избежать циклической ссылки, содержащей элемент DOM.
если обзор - такая большая проблема ... +1
Отлично ... Попробую. Я подозреваю, что вы категорически против, так как причина для назначения источника / фрагмента / ссылки, а не их прямого использования, заключалась в том, что они «таинственным образом» выходили за рамки. Замыкания JS! = Замыкания Perl!
Попытайтесь сократить свой код до минимума, в котором ошибка все еще присутствует.