Mohawk / Объектная модель

CMS*

Что такое Mohawk?


Mohawk (Мохавк или Могавк) — это JS-фреймворк, созданный для Ирокез CMS, и в нем же используемый. Первоначально фреймворк создавался как набор js-функций для создания кроссбраузерных скриптов, однако, впоследствии перерос в самостоятельный фреймворк.

Почему не jQuery или любой другой популярный фреймворк?

Дело в том, что когда создавался Ирокез, jQuery еще не было. В то время был очень популярен Prototype, а jQuery только набирал обороты. Но Prototype был больше популярен в RoR сообществе, поэтому я его не особо хотел использовать :)

Что умеет Мохавк?

На сегодняшний Мохавк — это полноценный кроссбраузерный js-фреймворк, который имеет следующие возможности:

— Создание объектов (объектная модель)
— Работа с DOM (переход по дереву, управление CSS классами и событиями, упрощение работы с DOM)
— Ajax интерфейс (включая упрощенную работу с формами)
— Перетаскивание и изменение размеров объектов
— Небольшой набор визуальных эффектов
— Шаблонизатор (js templates)
— UI компоненты (WYSIWYG, списки, табы, поля ввода и т.д.)

В этой статье, я хотел бы начать с описания объектной модели.

Объектная модель


Основной задачей объектной модели в Мохавке было наличие механизма наследование классов. При создании фреймворка в то время в основном были две популярные реализации ООП в js:
— определение класса как функцию, и последующее наследование через расширение прототипа функции (примерно, как то вот так: www.kevlindev.com/tutorials/javascript/inheritance/)
— метод из фреймворка base2 от Dean Edwards (http://code.google.com/p/base2/)

Первый метод не устраивал, т.к. при наследовании от наследуемного класса там начиналась просто беда с ссылками на родителя. Метод от Dean Edwards работал идеально, однако две вещи не давали покоя: 1. «klass» в качестве базового класса и 2. не было возможности ссылаться на родителя, а только на перезаписанный метод родителя. Впрочем, я несколько раз пытался изменить код под свои нужды, но там при разборе метода наследования мозги вскипали :) Если не ошибаюсь, то MooTools до сих пор использует этот метод в своем коде.

Итак, как же работает объектная модель в Мохавке.

Создание класса

Класс создается через функцию Class, единственным аргументом которой будет объект (тело) нашего класса:
var A = new Class({/*описание объекта*/});

* This source code was highlighted with Source Code Highlighter.


Создадим класс Person со свойством name, конструктором принимающим имя и методом hello:
var Person = new Class({
  // можно задать значение по умолчанию
  name: 'anonoymous',

  // конструктор
  __construct: function (name) {
    self.name = name; // присваиваем свойству объекта переменную
  },

  // метод
  hello: function () {
    Console.log('Hello, my name is ' + self.name);
  }
});

* This source code was highlighted with Source Code Highlighter.


Как можно увидеть из кода, конструктор задается через поле __construct переданного объекта (очевидно, на название повлиял PHP). Еще одно замечание: внутри методов класса ссылкой на класс является переменная self заместо обычного this. Причина тому в том, что this часто зависит от окружения, а переменная self будет постоянна. В методе hello я пишу сообщение в консоль Мохавка, чтобы в примере вы могли видеть, как оно работает. Как видно, в методе обращение к свойству name происходит через переменную self.
Посмотреть в действии можно здесь: demo.irokez.org/mohawk/
А скачать фреймворк с примером тут: irokez.org/download/mohawk/

Протестируем наш объект:
var alice = new Person('Alice');
alice.hello();

* This source code was highlighted with Source Code Highlighter.


В консоли увидим: «Hello, my name is Alice».

Наследование

Теперь создадим класс, производный от Person. Пусть это будет Student с дополнительным полем school, новым методом enters и перегруженным методом hello. Наследование выполняется через метод extends у созданного класса Person. Параметром также как и в Class передается «тело» наследуемого класса:
var Student = Person.extend({
  school: '',

  enters: function (school) {
    self.school = school;
  },

  // перегруженный метод
  hello: function () {
    // вызов родительского "перегружаемого" метода
    parent.hello();
    
    if (self.school) {
      Console.log('I study at ' + self.school);
    } else {
      Console.log('I don\'t study yet');
    }
  }
});

* This source code was highlighted with Source Code Highlighter.

Как видно из этого примера, ссылку к родителю можно получить через переменную parent.

Тестируем новый класс:
var bob = new Student('Bob');
bob.enters('MIT');
bob.hello();

* This source code was highlighted with Source Code Highlighter.


Вывод консоли:
Hello, my name is Bob
I study at MIT

Статические свойства и методы

В недавней версии в Мохавк были добавлены статические свойства и методы. Доступ к ним осуществляется через переменную static. Посмотрим пример:
var Phd = Student.extend({
  hi: function () {
    self.hello();
    
    Console.log('My degree is ' + static.degree);
  }
})

Phd.degree = 'PhD'; // статическое свойство (можно использовать как константу класса) degree

// создадим объект
var carol = new Phd('Carol');
carol.enters('MIT');
carol.hi();

* This source code was highlighted with Source Code Highlighter.


Консоль выдаст:
Hello, my name is Carol
I study at MIT
My degree is PhD

Синглтон

Иногда класс требуется только в одном экземпляре, для этого можно воспользоваться готовой функцией Singletone:
var ProfSmith = new Singletone({
  hello: function () {
    Console.log('Hello, I am Prof. Smith');
  }
});

ProfSmith.hello(); // Hello, I am Prof. Smith

* This source code was highlighted with Source Code Highlighter.


Как видно из примера, объект ProfSmith создается сразу же при его определении.

Синтаксический сахар

Ну и напоследок небольшой синтаксический сахар. Угадайте, что выдаст в консоль следующий код:
var sugar = new Singletone({
  a: function () {
    Console.log('I am called from method ' + __function__);
  },

  b: function () {
    Console.log('I am called from method ' + __function__);
  }
});

sugar.a();
sugar.b();

* This source code was highlighted with Source Code Highlighter.


В следующей статье постараюсь продолжить описание фреймворка, если будет вам интересно. Всем спасибо за внимание.

PS: если вы скачали фреймворк и используете ИЕ7, у Мохавка могут возникнуть некоторые разногласия с ИЕ7. Поэтому если есть возможность, запустите его через локальный веб-сервер, чтобы адрес был хотя бы localhost.
+14
6 марта 2009, 22:26
12
Irokez 56,7

комментарии (18)

+2
vflash #
понравилась функция

  getOpacity: function (opacity) {
    if (IE) {
      // ???
    } else {
      return this.style.opacity;
    }
  }

* This source code was highlighted with Source Code Highlighter.
0
Irokez #
с ИЕ к сожалению порой бывает сложно, как и в этом примере :)
если кто подскажет, как реализовать (учитывая, что ие не поддерживает css свойство opacity) — буду рад добавить во фреймворк
+1
aleks_raiden #
ну а как во всех других фреймворках сделано? пока не увидел ничего уникального, а раз это есть у других, значит возможно к реализации
–1
aps #
>если кто подскажет, как реализовать (учитывая, что ие не поддерживает css свойство opacity)
www.tigir.com/opacity.htm

М.б. все-таки стоит отказаться от фреймворка, у которого «разногласия с IE7» и как выяснилось с ie6? и в prototype и в jquery эти вещи давно решены.
0
mustafin #
Честно говоря, я слабо понимаю условие на IE в функции getOpacity, разве что для того, чтобы фреймворк был совсем универсален.

Я давно уже не встречал верстки только под IE, кроссбраузерно же все устанавливают 2 свойства и opacity и filter:alpha. Поэтому в большинстве случаев this.style.opacity более чем достаточно.

Если же хотите абсолютной универсальности, то как минимум стоит использовать функцию getStyle, т.к. далеко не всегда стили прописываются inline, а для IE не вижу сложности, вам просто нужно разобрать строку.

Или я что-то не понимаю?
+1
Irokez #
Странно, что все сразу бросились на getOpacity, хотя эта функция применяется очень редко, а критикуют ее, как будто это основа всего фреймворка :)
В общем, функция понадобилась для получение прозрачности элемента. Применяется она пока в единственном случае: при плавном изменении прозрачности элемента в эффектах (к примеру исчезновение или появление элемента). Тут и нужна функция — перед использованием эффекта нужно запомнить изначальное значение прозрачности, чтобы потом его можно было восстановить.
В браузерах, поддерживающих CSS свойство это сделать просто. В ИЕ я подозреваю, придется парсить свойство filter. Но в большинстве случаев, элементы не являются прозрачными (т.е. opacity = 1), поэтому workaround был — просто вернуть элемент в непрозрачное состояние, а дописание функции было отложено до того момента, когда она действительно понадобится. Пока что такого момента не наступило.
+2
magmoro #
странно реализована функция toHex, почему не просто: number.toString(16).toUpperCase()
0
Irokez #
не странно, а скорее «в лоб» :) спасибо, заменю на ваш вариант
–2
Octane #
Вечно программисты, пришедшие с PHP, начинают подобие статической классовой модели лепить в Javascript. Потом еще и идеи MVC в элементы интерфейса будете внедрять наверное :-)
Зачем лепить из одного языка, другой, ну удобно вам наследование организовывать, как в классах, так сделайте простенький конструктор, зачем эти всякие singleton, static и private в Javascript, где вы их будете применять? Да и вообще в большинстве случаев достаточно одной, максимум двух, функции-конструкторов с наследованием по прототипу для создания любого интерфейса в Javascript. Все остальное лишь добавляет в фреймворк лишний код, неоправданные межкомпонентные связи и, как следствие, снижает производительность, которой Javascript и так похвастаться не может, особенно в старых браузерах.
0
Irokez #
Ну, если честно, я это применяю в повседневной разработке.
Наследование особенно удобно в UI интерфейсах. К примеру, у нас есть список, который мы можем расширить до дерева, до списка с перетаскиваемыми элементами или с сортируемыми.
На скорости, я бы не сказал, что это пагубно влияет, к тому же современные браузеры ускоряют выполнение javascript (взять тот же гугл хром с V8 и новый сафари, который его даже опережает по скорости). При том, что скорость разработки это существенно увеличивает.
Singletone и static — это просто синтаксический сахар. На скорость это абсолютно не влияет, зато радует глаз при написании кода, да и просто удобно.

PS: ну и не совсем понял причем тут PHP :) я бы сказал, программисты на яве были бы более склонны к объектной модели для javascript
0
akzhan #
Sizzle прикрутите?)
0
Irokez #
Возможно, в планах есть добавить такой функционал.
При Sizzle, если честно, первый раз слышу. Нашел страницу проекта, изучаю :)
0
mustafin #
Полностью поддерживаю…
JS любить и понимать надо, а не переделывать визуально синтаксис под что-то.

Это мне напоминает… подмену для C, чтобы было похоже на Pascal.

#define begin {
#define end }
0
Irokez #
Я и так люблю и понимаю яваскрипт, но при этом отсутствие привычного ООП очень не хватает при разработке.
Не зря все таки в новой версии хотят ввести полноценное ООП (http://www.ecmascript.org/es4/spec/overview.pdf)
+2
f33l #
а почему не mootools-то? судя по всему, у вас получится почти копия, какой в этом смысл? чем ваш фреймворк лучше/отличается от мутулс?
0
Irokez #
да не было тогда еще mootools :)
кстати, в mootools меня не совсем устраивает синтаксис при создании классов
0
f33l #
тогда не было, а щас есть ) это как раз тот случай, когда лучше не увеличивать энтропию. если вы хотите сделать полноценный фреймворк, обойти мутулс будет очень сложно, там все уже вылизано и отточено.
имхо было бы несравнимо полезнее, если бы вы поучаствовали в популяризации мутулс, у них как раз не хватает евангелистов, да и плагинов еще можно много сделать, хоть и есть www.clientcide.com/js и т.п.
и ведь вам придется тратить лишнее время на поддержку вашего фреймворка, которое вы могли бы потратить на вашу цмс, например. цмс это все таки платформа, а js-библиотека это всего лишь один из компонентов.

>кстати, в mootools меня не совсем устраивает синтаксис при создании классов
а чем? я что-то не вижу различий. плюс там есть options/events-сахар, implement и т.д.
+1
Frenzy #
...Prototype был больше популярен в RoR сообществе, поэтому я его не особо хотел использовать :)


конструктив. ога

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.