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

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

    Как использовать


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

    * This source code was highlighted with Source Code Highlighter.

    Где:
    • base — базовый тип (если он есть)
    • methods — перекрываемые и новые методы
    • statical — статические свойства и методы

    «Магические» методы и свойства


    Кроме этого, есть несколько «магических» методов:
    • __constructor — метод, вызываемый при создании экземпляра
    • __base — метод, позволяющий вызвать одноименный метод базового типа
    • this.__self — так изнутри можно получить доступ к статическим свойствам и методам

    Пример


    // Базовый тип
    var A = $.inherit(
      {
        __constructor : function(property) {
          this.property = property;
        },
        getProperty : function() {
          return this.property;
        },
        getStaticProperty : function() {
          return this.__self.getStaticProperty();
        }
      },
      {
        staticProperty : 'static property of A',
        getStaticProperty : function() {
          return this.staticProperty;
        }
      });

    // Производный тип от А
    var B = $.inherit(
      A,
      {
        getProperty : function() {
          return this.__base() + ' in B';
        }
      },
      {
        staticProperty : 'static property of B',   
      });

    var instance = new B('value');
    alert(instance.getProperty());
    alert(instance.getStaticProperty());
    alert(B.staticProperty);

    * This source code was highlighted with Source Code Highlighter.
    Сам плагин можно скачать отсюда.
    Share post

    Comments 14

      0
      1. чем не устроил вариант base2 и другие велосипеды?
      2. колько стоит в твоей реализации делегирование? covex-nn.ya.ru/replies.xml?parent_id=1745&item_no=1698&with_parent=1#reply-covex-nn-1745 — тут base, prototype и resig показали себя не слишком хорошо
      3. на тему пропертей: groups.google.com/group/jfix-javascript-framework/browse_thread/thread/2def43a808fbc9e0
        0
        1. base2 делает очень много, мой взгляд, лишних телодвижений. Велосипед Резига откровенно не доделан. В свой велосипед я собрал минимум того, что мне нужно.
        2. Если тебе правда интересны такие тесты, я попозже измерю. Но: ты же не меряешь, например, скорость $.each и while, хотя и ежу понятно, что первый медленнее второго. А если у твоей системы основное время работы составляет создание объектов, может тебе стоит посмотреть на техники, позволяющие уменьшить количество объектов?
        3. По поводу пропертей, в вышеприведенном примере property и getProperty — это просто чтобы показать как работает наследование и перекрытие, а не чтобы продемонстрировать какую-то технику работы с проперти. Если тебя смущает getProperty() — замени его на doFoo().

        В последнее время слышу очень много разговоров по поводу наследование vs агрегирование/делегирование. Для меня это не взаимоисключающие парадигмы, а взаимодополняющие, каждая из которых применяется там, где она лучше подходит.
          0
          1. так что же тебе нужно?
          2. там проблема не в создании объектов, а в том, что каждый вызов метода становится дорогой операцией
            0
            1. мне нужен минимум инструментов, позволяющий работать с наследованием

            Померял твоей «пиписькомеркой»:


            То, что измеряется в этих тестах, слишком далеко от реальной жизни. Как только методы начнут не просто делегировать вызовы своему предку, а выполнять еще какие-то действия (ведь именно за этим они перекрывают базовые методы), то тут же этот разрыв начнет резко падать. А так это средняя температура по больнице. Плюс еще тесты некорректны — очень сильно скачет разброс результатов от запуска к запуску.
        0
        А при чём здесь jQuery? А обёртка для связки прототипов, задания базового конструктора и прочий дополнительных полезных слотов занимает 4-15 строк.
          0
          Если на проекте в качестве основного фреймворка используется jQuery, то и все остальное, расширяющееся базовый функционал, я предпочитаю оформлять в jQuery-style. Вас же не смущает, что в jQuery есть $.extend или $.makeArray?

          А можно увидеть ваши 4-15 строк, делающий все перечисленное в статье?
            0
            > А можно увидеть ваши 4-15 строк, делающий все перечисленное в статье?

            Самый простой и классический пример (паттерн).

            function inheritePrototype(child, _super) {
                var __inheritance = function () {};
                __inheritance.prototype = _super.prototype;
                child._super = _super;
                child.prototype = new __inheritance();
                child.prototype.constructor = child;
            }
            
            // пример
            
            function A() {
              this.state = 10;
            }
            
            A.prototype.test = function () {
              alert('A.test');
            };
            
            function B() {
              B._super.apply(this, arguments);
            }
            inheritePrototype(B, A);
            
            B.prototype.test = function () {
              B._super.prototype.test.apply(this, arguments);
              alert('B.test');
            };
            
            var b = new B();
            b.test();
            alert(b.state);
            
            

            Естественно, можно оформить в нужном виде (например, свойством функции или ещё как), но внутренности — есть одна из реализаций, того, что Вам нужно. Можно наследоваться, вызвать одноименные методы и базового конструктора. То, что у Вас названо статическими свойстами — можно так же положить в прототип, или сделать свойствами коструктора.
              0
              да, похожий кусок есть и в моем коде, только этого недостаточно:

              B._super.prototype.test.apply(this, arguments); — некрасиво и неудобно, я сам когда-то так делал. Гораздо удобнее писать this.__base() для всех методов, а не думать постоянно о том, кто базовый класс и писать эту длинную однообразную простыню.
              — конструктор разнесен с методами, это тоже неудобно и некрасиво
              — как вы сами заметили, нет статики

              Собственно мой код и крутится вокруг того, чтобы обеспечить некий syntax sugar. Что конкретно вы считаете в нем лишним?
                0
                > B._super.prototype.test.apply(this, arguments); — некрасиво и неудобно… Гораздо удобнее писать this.__base()

                да естественно, я лишь пример привел, можно хоть как подогнать под свои нужды, под синтаксис, который кажется удобным

                > конструктор разнесен с методами, это тоже неудобно и некрасиво

                да это мелочи всё, дописывается ещё «2-3» строками

                > как вы сами заметили, нет статики

                А что Вы подразумеваете под статикой?

                > Собственно мой код и крутится вокруг того, чтобы обеспечить некий syntax sugar.

                А я ничего против и не имею. Каждый создаёт свои обёртки, которые наиболее удобны для него. Наследование же в JS и так изначально есть, поэтому любая обёртка — есть обёртка, и является лишь синтаксическим сахаром, определяющим относительное удобство.

                > Что конкретно вы считаете в нем лишним?

                Да нет, лишним в подобных обёртках мало, что может быть, поскольку они относительные, и пишутся для удобства, увиденное через призму конкретных людей. Под «лишним» я больше имел в виду привязку к jQuery, но Вы уже ответили, зачем он тут.
                  0
                  > да это мелочи всё, дописывается ещё «2-3» строками

                  Да это понятно, что мелочи — просто из кучки таких мелочей в итоге и вырастает чуть побольше

                  > А что Вы подразумеваете под статикой?

                  Конкретно тут я имею ввиду свойства типа, а не его экземпляра. Тоже мелочь, а приятно :)
                    0
                    > Конкретно тут я имею ввиду свойства типа, а не его экземпляра. Тоже мелочь, а приятно :)

                    ну так и говорю — хранить в конструкторе или так же — в прототипе
          0
            0
            Этот вариант недоделан, о чем можно прочитать в комментах того поста.
            0
            Привет, спасибо за решение.
            Подскажи, как ты работаешь с данным примером.
            Опять этот scope…

             var Test = $.inherit(
              {
                __constructor: function() {	
            		$('body').on('click', 'a', this.onLinkClick);
            		// or
            		// var self = this;
            		// $('body').on('click', 'a', $.proxy(this.onLinkClick, this));
                },
            
                onLinkClick: function() {
            		? доступ к this Test
            		? доступ к this 'a'
            		return false;
                }
            });
            

            Only users with full accounts can post comments. Log in, please.