Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 10.07.2008, 00:50
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Ссылка на объект при использовании attachEvent
Здравствуйте.
Есть код
function addEvent(obj, type, listener) {
        if(obj.addEventListener) {
                obj.addEventListener(type, listener, false);
        }
        else if(obj.attachEvent) {
                obj.attachEvent('on' + type, function() {listener.apply(obj);});
        }
}

function $(id) {
        var obj = document.getElementById(id);
        obj.bind = function(type, listener) {
                addEvent(this, type, listener);
                return this;
        }
        return obj;
}

Допустим выполняем такую конструкцию:
$('id').bind('click', function() {
        alert(this);
});

Для того, чтобы в IE(любой версии) по ссылке this был доступен объект, полученный через $('id') пришлось добавить в attachEvent вот эту конструкцию:
function() {listener.apply(obj);}

но теперь не ясно как реализовать detachEvent ?
Помогите пожалуйста разобраться :confused:

Последний раз редактировалось Octane, 10.07.2008 в 01:00.
Ответить с цитированием
  #2 (permalink)  
Старый 11.07.2008, 16:10
Аватар для Snipe
Профессор
Отправить личное сообщение для Snipe Посмотреть профиль Найти все сообщения от Snipe
 
Регистрация: 06.05.2008
Сообщений: 765

Если честно, не понял в чем суть. В данном вопросе обе функции принимают участие и про какой this идет речь?
Ответить с цитированием
  #3 (permalink)  
Старый 11.07.2008, 19:07
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

this, который в
$('id').bind('click', function() {
        alert(this);
});

При использовании addEventListener все работает отлично, this - возвращает объект, который мы получаем при вызове первой функции $('id'), но при использовании attachEvent, ссылка this - ведет на объект window. Чтобы выполнить добавляемую в обработчик события функцию в контексте объекта, к которому она привязывается, записываем attachEvent следующим образом:
obj.attachEvent('on' + type, function() {listener.apply(obj);});

Но теперь получается, что если мы передадим имя функции в метод bind:
$().bind('click', fn);
то для ИЕ невозможно выполнить detachEvent, т.к. у нас всегда привязывается абстрактная функция... Вот я и спрашиваю как переделать код, чтобы внутри метода bind, объект к которому привязывается функция был доступен по ссылке this, т.е. привязываемая функция выполнялась бы в контексте этого объекта, но можно бы было выполнить detachEvent :rolleyes:

Последний раз редактировалось Octane, 11.07.2008 в 19:44.
Ответить с цитированием
  #4 (permalink)  
Старый 12.07.2008, 01:00
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

Octane,

- если вы хотите detach'ить хэндлер, то при attach'e он не должен быть анонимным (т.е. функцию надо описать до этого);

- использование apply'я внутри обертки - это, конечно, хорошо (не надо каждый раз писать при добавлении события), но тогда, придется запоминать вновь созданную функцию (как свойство объекта), чтобы получить возможно удалить при detach'e. Поэтому, альтернативной может быть - apply "снаружи" перед bind'ом события к элементу (внутри, естественно, apply'ить (obj.attachEvent('on' + type, function() {listener.apply(obj);}); ) тогда уже не надо):

// вспомогательный wrapper для привязки this
Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    return __method.apply(object, arguments);
};

function a() {
  alert([this.tagName, this === window]);
}

var obj = $('test');
var handler = a.bind(obj);

obj.bind('click', handler);
obj.unbind('click', handler); // и тогда можно будет detach'ить


P.S. не очень удачно два раза название bind в разных местах получилось, но, думаю, путаницы не вызовет.

P.S.[2]: все методы для расширения объектов лучше вынести в отдельное место и при расширении ссылаться на них, а не создавать каждый раз новую анонимную функцию (это сэкономит ресурсы). А для FF и Opera можно вообще расширить прототип глобального объекта HTMLElement (и тогда все это будет храниться в одном месте; хотя для IE в этом случае так же можно использовать behavior и expression, но это уже отдельная песня и там свои косяки у expression с производительностью).
__________________
Тонкости ECMAScript

Последний раз редактировалось Dmitry A. Soshnikov, 12.07.2008 в 01:05.
Ответить с цитированием
  #5 (permalink)  
Старый 12.07.2008, 01:57
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Спасибо большое, отлично работает. Больше недели голову ломал, как это сделать, даже не подумал чот о встроенном объекте Function, хотя идея про обертку возникала, только не знал как реализовать.
Для удобства наверное сделаю автоматическую привязку
var handler = a.bind(obj);
внутри метода
obj.bind('click', handler);

--------------
эмм нет, не получится автоматической привязки, тогда всегда будет аттачиться функция с именем handler. Придется тогда перед attachEvent проверять, что нам пришло, если абстрактная функция, то автоматически делаем apply как было раньше, если имя функции, то так и передаем ее в attachEvent... а как проверить тип функции? %)

Последний раз редактировалось Octane, 12.07.2008 в 02:05.
Ответить с цитированием
  #6 (permalink)  
Старый 12.07.2008, 14:02
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

> если абстрактная функция, то автоматически делаем apply как было раньше

Вы ж с этого начали - вам надо detach'ить хэндлеры; но если будет передана анонимная функция при атаче, то нельзя будет сделать detachEvent и removeEventListener (прочитайте мой первый пункт выше). Передавая каждый раз анонимную функцию - вы каждый раз содаете новую функцию. И то, что вы внутри сделаете var handler = ... - это тоже не спасет, т.к. опять не известно, что передавать при detach'e (если только handler у вас не глобальная функция будет, но это уже не правильно).

Поэтому привязывать к this надо снаружи и передавать уже привязанную функцию - одну и ту же - и при атаче и при детаче.

P.S.:

> а как проверить тип функции? %)

"тип функции" тут не совсем подходит - вам же прсто надо узнать есть имя у функции или нет; в FF можно проверить свойство name. Но сработает это только для функции типа declaration:

function a() {};
alert(a.name);


но уже не сработает для типа statement:

var a = function () {}; // один из разновидностей statement'а функции
alert(a.name);


Поэтому кроссбраузерно, можно привести функцю toString'ом и найти имя (или пустоту в случае анонимной функции и некоторых statement'ов).

Но все это не нужно для вашего таска, поэтому в P.S. вынес =)
__________________
Тонкости ECMAScript
Ответить с цитированием
  #7 (permalink)  
Старый 12.07.2008, 18:56
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

я прекрасно понимаю, что если передать в метод объекта bind абстрактную функцию, то потом ее нельзя будет детачить, но нам это и не надо, для абстрактных функций выполним автоматическое взятие контекста:
obj.attachEvent('on' + type, function() {listener.apply(obj);});

А вот, чтобы иметь возможность детачить функции и передаем в метод bind имя функции (или ссылку на абстрактную в случае с statement). Но в этом случае надо первоначально получить контекст в котором она будет выполняться:
var handler = a.bind(obj);

т.к. функции привязки событий только часть базовой основы будущего проекта и пользоваться ими придется не только мне, то я более чем на 100% уверен что программисты будут забывать выполнять var handler = a.bind(obj); перед привязкой функции к событиям объекта, что в случае появления необходисмости использования this приведет к длительному поиску ошибки, где же всетаки забыли выполнить обертку, притом это только для IE... поэтому и заговоил об автоматизации этого действия var handler = a.bind(obj);

А вот с определением того, в каком виде передана функция, получается что регулярным выражением мы найдем и абстрактную функцию и statement одинаково :-(
Ответить с цитированием
  #8 (permalink)  
Старый 12.07.2008, 21:44
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

Сообщение от Octane
нельзя будет детачить, но нам это и не надо
а =) ну, вероятно, цель просто изменилась в процессе; это нормально. Однако, первоначальный основной вопрос в первом посте был именно про это:

Сообщение от Octane
но теперь не ясно как реализовать detachEvent ?
Помогите пожалуйста разобраться
Ну да ладно, не надо детачить в вашем случае теперь - значит не надо =)

Сообщение от Octane
получается что регулярным выражением мы найдем и абстрактную функцию и statement одинаково :-(
к сожалению, да

Сообщение от Octane
абстрактную функцию
анонимную
__________________
Тонкости ECMAScript

Последний раз редактировалось Dmitry A. Soshnikov, 12.07.2008 в 21:47.
Ответить с цитированием
  #9 (permalink)  
Старый 12.07.2008, 22:25
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

детачить анонимную функцию не надо, если планируется использовать detachEvent, то в метод bind надо передавать имя функции или переменную содержащую функцию.

абстрактную - анонимную, в разной литературе встречаются оба эти понятия, думаю они значат одно и то же
Ответить с цитированием
  #10 (permalink)  
Старый 12.07.2008, 23:43
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

Сообщение от Octane
если планируется использовать detachEvent, то в метод bind надо передавать имя функции или переменную содержащую функцию
ну да, именно об этом и велась речь

Сообщение от Octane
абстрактную - анонимную, в разной литературе встречаются оба эти понятия, думаю они значат одно и то же
Ни в коем случае не считайте за цепляние к словам =)), но, я думаю, главное - это, все же, стремление к истине, поэтому все же стоит сказать:

Термин абстрактный метод (реже - абстрактная функция) - применяется для резервирования (имени) метода в абстрактном классе, с целью последующей перегрузки в классе-наследнике. Т.е. абстрактная функция не может существовать сама по себе. В свою очередь анонимная функция (лямбда) - это полноценно-рабочая функция, но не имеющая своего идентификатора (можно положить ссылку на нее в переменную, но это не идентификатор функции, как в случае с function-declaration). В JS термин "абстрактная функция" не употребляется.

В JavaScript внутри функции можно сослаться на нее саму через специальное свойство callee в объекте arguments; это дает возможность анонимным функциям быть рекурсивными:

(function () {
  alert(arguments.callee);
})();
__________________
Тонкости ECMAScript

Последний раз редактировалось Dmitry A. Soshnikov, 13.07.2008 в 00:02.
Ответить с цитированием
Ответ


Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Кодировка при использовании Ajax Nichloas AJAX и COMET 9 17.09.2009 16:06