13 апр. 2009 г.

Плагин для jQuery, реализующий наследование

Недавно понадобилось для проекта с jQuery реализовать наследование, написал плагин для jQuery, где релизованы идеи, описанные в «Еще раз о наследовании в JavaScript». Плагин находится на code.google — code.google.com/p/jquery-inheritance/

Работает так:

$.inherit([base], methods, [statical])

Пример:

// A — базовый тип
var A = $.inherit(
    {

        // __constructor — специальный метод, вызываемый при создании экземпляра
        __constructor : function(property) {
                this.property = property;
        },

        getProperty : function() {
            return this.property + ' of A';
        },

        getType : function() {
            return 'A';
        }

    },
    {
        // статическое свойство, доступное изнутри как this.__self.staticMember
        staticMember : 'staticA'
    });

// B — тип, наследуемый от A
var B = $.inherit(
    A,
    {

        // перекрытие с вызовом одноименного метода базового класса
        getProperty : function() {
            return this.__base() + ' of B';
        },

        // просто перекрытие
        getType : function() {
            return 'B';
        }

    },
    {
        staticMember : 'staticB'
    });

var instance = new B('value');

console.log(instance.getProperty());
console.log(instance.getType());
console.log(instance.__self.staticMember);

А кто вообще как использует, и использует ли вообще, наследование?

9 комментариев:

Анонимный комментирует...

Я использую Base, расширенный методами bind, unbind и trigger. Всё собираюсь написать заметку про это.

alpha комментирует...

Одна из идей (про вызов одноименного метода базового класса), реализованных в моем плагине, как раз заимствована из base2 :)

Получается, что у тебя все "классы" имеют bind, unbind, trigger?

Анонимный комментирует...

Ну да. Bind и unbind являются обёртками для jQuery.event.addWithContext (позволяет передавать контекст обработчика) и jQuery.event.remove, а вот trigger пришлось написать с нуля: в jQuery он делает много лишних телодвижений.

Получается довольно понятный и компактный код как для обычных, так и для jQuery-объектов:

jQuery('#foo').bind('click', this._onFooClick, this);
this._bar.bind('Enable', this._onBarEnable, this);

alpha комментирует...

jQuery('#foo').bind('click', this._onFooClick, this);

Переопределен нативный bind в jQuery?

Анонимный комментирует...

Ага.

Иван комментирует...

Обожаю Jquery

www.profdesigner.com

Ti комментирует...

Прежде всего спасибо за плагин ;)

Через некоторое я время столкнулся со следующей проблемой:
Когда метод объекта назначается на событие, метод выполняется в контекста объекта в котором сработало событие => в методе никак не добраться до исходного объекта
$('#id').click(instance.method)
Тоже самое и для статических методов.

Обычно, проблема решается так:
$('#id').click(function() { instance.method() })

В добавок мне нужно было сделать unbind события. Хранить где-то новый callback не удобно.

По-этому я решил исправить эту проблему в самом jQuery.inherit:
http://ti-webdev.blogspot.com/2009/10/jquery.html

Буду рад если изменения попадут в google code.

alpha комментирует...

to Ti: У вас на каждое инстанцирование объекта делается не совсем легкая операция replaceMethodContent(this);. Как-то меня это очень смущает.

osdm комментирует...

Спасибо за плагин. Не подскажете, почему вызов базового метода не обернут в try-finally? Это просто оптимизация путем забивания на редко используемые exception-ы или что-то другое?

this.__base = baseMethod;
try {
var result = overrideMethod.apply(this, arguments);
} finally {
this.__base = baseSaved;
}