#javascript #closures #dom-events
#javascript #замыкания #dom-события
Вопрос:
У меня есть рабочая версия загрузчика файлов перетаскиванием HTML5. Я редактировал код JS для поддержки нескольких загрузок файлов на одной странице. Я столкнулся с проблемой, пытаясь получить доступ к свойствам «экземпляра» в методах, которые зарегистрированы как события.
Проблема показана приведенным ниже кодом в методе this.drop
. Причиной существования this.$$upload_self
свойства является доступ к данным через это свойство. Например, я не могу использовать this
ключевое слово внутри this.drop
функции, потому что при возникновении события, this
не ссылающегося на мой «экземпляр».
Я не уверен, что создание $$upload_self
было хорошей идеей.
Область новых экземпляров создана следующим образом:
var recording_upload = new upload();
recording_upload.init(recording_upload, ...);
Код загрузки файла перетаскиванием:
var upload = function() {
this.$$upload_self = null;
this.$drop = null;
this.$status = null;
this.$progress = null;
this.maxNumberOfFiles = null;
...
this.init = function (self, pUrl, maxNmbOfFiles, dropArea, progress, status) {
$$upload_self = self;
$$upload_self.postUrl = pUrl;
$$upload_self.maxNumberOfFiles = maxNmbOfFiles;
$$upload_self.$drop = $("#" dropArea);
$$upload_self.$progress = $("#" progress);
$$upload_self.$status = $("#" status);
$$upload_self.$drop.bind('dragenter', $$upload_self.enter);
$$upload_self.$drop.bind('dragleave', $$upload_self.leave);
$$upload_self.$drop.bind('drop', $$upload_self.drop);
};
this.enter = function (e) {
$(e.target).addClass('hover');
return false;
};
this.leave = function (e) {
$(e.target).removeClass('hover');
return false;
};
this.drop = function (e, _this) {
$(e.target).removeClass('hover');
var files = e.originalEvent.dataTransfer.files;
if (files.length > $$upload_self.maxNumberOfFiles) { // for example, here $$upload_self references always last instance...
$$upload_self.displayErrorMessage('Error: You can only drop ' $$upload_self.maxNumberOfFiles ' file(s) at time.');
return false;
}
...
};
...
}
Есть ли какой-либо обходной путь для решения этой проблемы? Я полагаю, что это, возможно, распространенная проблема, но не могу найти ничего, чтобы решить эту проблему.
Любая помощь очень ценится.
Ответ №1:
Вы могли бы вообще отказаться от new
ключевого слова и использовать новое замыкание для каждого экземпляра upload
.
РЕДАКТИРОВАТЬ: обновлено, чтобы избежать потенциального сглаживания глобального this
.
var upload = function(pUrl, maxNmbOfFiles, dropArea, progress, status) {
return {
postUrl: pUrl,
...
drop: function(e) {
...
if (files.length > this.maxNumberOfFiles) {
this.displayErrorMessage(...);
}
...
},
...
};
};
...
var someUpload = upload(...);
Ответ №2:
Попробуйте выполнить поиск «области видимости». В качестве примера посмотрите, как это реализовано в ExtJS.
Комментарии:
1. На самом деле это не проблема области видимости; это проблема с семантикой вызовов функций и
this
.2. Это «область видимости» в терминах ExtJS. Не переменная область видимости, но может быть некоторый контекст — я не знаю более правильного универсального слова.
Ответ №3:
В современном браузере вы можете сделать это:
$$upload_self.$drop.bind('dragleave', $$upload_self.leave.bind($$upload_self));
Для более старых версий IE вы можете сделать это:
$$upload_self.$drop.bind('dragleave', function() { $$upload_self.leave(); });
На самом деле метод «.bind()» для всех функциональных объектов в новых браузерах просто создает для вас небольшую промежуточную функцию, по сути, похожую на второй пример. На странице документов Mozilla для «.bind()» есть очень хороший блок кода, который вы можете использовать в качестве исправления «полизаполнения» для браузеров, которые не поддерживают «.bind()» изначально.