Pull to refresh

Enyo 2. ООП

Reading time 5 min
Views 6.4K
image

Первый топик постигла участь многих пятничных постов, но не беда!
Я не сдаюсь, а значит мы продолжаем…

В этом топике мы осветим следующие темы:
  • Классы. Определение, создание экземпляров, наследование.
  • Методы и поля классов, конструкторы и методы базового класса


Disclaimer


Хабражители, я не претендую на истину в последней инстанции.
Мои познания JS и Enyo в частности — довольно ограничены, а потому tutorial является неполным.
Я настоятельно рекомендую всем заинтересовавшимся ознакомиться с офф. документацией.
Ссылки доступны в первой части, в приложении к текущему топику и конечно на enyojs.com.

Исходные данные


Использовать будем все тот-же файл «index.html»:
<!DOCTYPE html>
<html>
  <head>
    <meta charset=utf-8>
    <title>Title</title>
    <link rel="stylesheet" href="http://enyojs.com/enyo-2.2.0/enyo.css"><!--Стили Enyo 2.2.0-->
    <script type="text/javascript" src="http://enyojs.com/enyo-2.2.0/enyo.js"></script><!--Сам Enyo 2.2.0-->
  </head>
  <body>

  <script type="text/javascript">
  </script>

  </body>
</html>

Все примеры будут изменять код внутри тега .

Классы. Определение, создание экземпляров, наследование.


Определение своих типов:
class ClassName {}

в Enyo конструкция будет иметь следующий вид
enyo.kind({name: 'ClassName'})


Создание экземпляра объекта не отличается оригинальностью:
var class_name = new ClassName()


Наследование немногим сложнее создания экземпляра:
class ClassNameA {}
class ClassNameB extends ClassNameA {}

в Enyo примет следующий вид:
enyo.kind({name: 'ClassNameA'})
enyo.kind({kind: 'ClassNameA', name: 'ClassNameB'})

Тут стоит оговориться: если в классических ООП языках экземпляр типа «ClassName» ссылается на участок памяти и не имеет каких либо выдающихся особенностей (в лучшем случае наследуется от класса Object), то в Enyo базовым классом по-умолчанию будет «enyo.Control» — блочный DOM-элемент с тегом div (суровое WEB наследие), т.е. для типа «ClassNameA» неявно базовым классом назначен «enyo.Control». Если это положение дел Вас не устраивает — наследуйте «enyo.Component».
Множественное наследование в стиле С++/Java/etc. обнаружить не удалось, везде где можно — утиная типизация, хотя может плохо искал.

Практикум


Возьмем наш «index.html» и впишем следующий код:
//Определяем наши классы
enyo.kind({name: 'ClassNameA'})
enyo.kind({kind: 'ClassNameA', name: 'ClassNameB'})

//Создаем экземпляры объектов
var cls_a = new ClassNameA()
var cls_b = new ClassNameB()

//Выведем объекты в консоль
console.dir(cls_a)
console.dir(cls_b)

Если проверить DOM то мы не обнаружим div элементов. Это связано с тем что ни у одного из классов не был вызван метод «renderInto()», тем не менее объекты, были созданы и инициализированы.

Методы и поля классов, конструкторы и методы базового класса


Классы — это хорошо, но зачем класс если не наполнять его функционалом? — Сейчас сделаем!
Имея псевдокод:
class ClassNameA {
  object fieldName = "value"
}

превратим в Enyo код:
enyo.kind({name: 'ClassNameA', fieldName: 'value'})

Теперь мы можем создать экземпляр класса и проверить что поле класса доступно:
var cls_a = new ClassNameA()
console.log(cls_a.fieldName)


Ок, но поля сами по себе мало что значат, где методы? — Да тут же, рядом!
Имея псевдокод:
class ClassNameA {
  object method () {
    return "value"
  }
}

превратим в Enyo код:
enyo.kind({
  name: 'ClassNameA',
  method: function(){ return 'value' }
})

Теперь мы можем создать экземпляр класса и проверить что метод класса доступен:
var cls_a = new ClassNameA()
console.log(cls_a.method())


Ок, есть поля, есть методы… может еще и конструктор/деструктор есть? — Конечно! Конструкторов аж 2 штуки!!! Но, будем последовательны.
При создании любого Enyo объекта вызывается его метод constructor, если необходима инициализация — стоит его переопределить.
Выглядит это следующим образом:

enyo.kind({
  name: 'ClassNameC',
  constructor: function() {
    // Собственно конструктор
    console.log('constructor')
  }
})

Для обращения к методу (в данном случае конструктору) базового класса в Enyo предусмотрена конструкция this.inherited(arguments). Стоит отметить что this.inherited(arguments) работает для всех методов которые вы планируете переопределять.
Как следствие код станет следующим:

enyo.kind({
  name: 'ClassNameC',
  constructor: function() {
    console.log('my init befor constructor')
    this.inherited(arguments)
    console.log('my init after constructor')
  }
})


Все вышеописанное справедливо для всех объектов Enyo создаваемых пользователем, но тут есть дополнение…
Тип «enyo.Component» — если вкратце, то этот зверь является одним из базовых классов для «enyo.Control» (того самого который по-умолчанию div).
Среди его полей и методов значатся:
  • name — поле отвечающее за типизацию/именование объектов
  • createComponent / createComponents — методы для динамического создания дочерних компонентов
  • destroyComponents — методы для динамического удаления дочерних компонентов
  • owner — поле-ссылка на родителя текущего компонента
  • id — думаю и так понятно
  • и много вкусных методов по работе с event-ами, но о них в следующих топиках

Как ни крути, а такой функционал достоин внимания. Так вот этот самый «enyo.Component» вводит еще 2 метода в жизненный цикл своих «детей»:
enyo.kind({
  name: 'ClassNameD',

  // Этот метод был рассмотрен ранее
  constructor: function() {
    this.inherited(arguments);
  },

  // Этот метод вызывается при createComponent / createComponents
  create: function() {
    this.inherited(arguments);
  },

  // Этот метод вызывается при destroyComponents
  destroy: function() {
    this.inherited(arguments);
  }
});


В чем соль? Да все очень просто!
Внутри «enyo.Component» и в частности «enyo.Control» может быть вложено множество элементов, а внутри них еще и т.д.
Как строить это дерево? Как связывать это дерево с DOM? Как пересчитывать размеры при добавлении / удалении элементов?
Как привязать / удалить event-ы? Чувствуете? Ага, свой маленький граф объектов с шашками и поэтессами!
Ради справедливости спешу сообщить что создание / удаление элементов и их фактическая отрисовка в DOM разнесены функционально.

Создание/Удаление дочерних элементов при создании нового экземпляра происходит по create/destroy. Доступ к вышестоящему узлу осуществляется по полю «owner», а к дочерним узлам по «this.$»
Офф. документация гласит: если ваш объект унаследован от «enyo.Component» или его потомков — используйте в качестве конструктора create т.к. он вызывается сразу после constructor, в противном случае — constructor.
Итог:
enyo.kind({
  name: 'ClassNameD',

  create: function() {
    // this.$ - пуст
    this.inherited(arguments)
    // this.$ - содержит дочерние элементы, и их методы create уже завершены
  },

  destroy: function() {
    // this.$ - содержит дочерние элементы
    this.inherited(arguments);
    // this.$ - пуст
  }
});


Ссылки


Наследование в Enyo. GitHub wiki Enyo
Object lifecycle Enyo. GitHub wiki Enyo
enyo.Component. Enyo API
enyo.Control. Enyo API
Only registered users can participate in poll. Log in, please.
Как подан материал?
30.95% Больше так не делай. Давай лучше переводы Enyo wiki. 13
19.05% Стоит подумать над стилистикой, но в любом случае это лучше перевода «в лоб». 8
50% Все класс! Давай еще. 21
42 users voted. 46 users abstained.
Tags:
Hubs:
+3
Comments 9
Comments Comments 9

Articles