Enyo 2. ООП

в 23:08, , рубрики: Enyo, javascript, web-разработка, метки: , ,

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>

Все примеры будут изменять код внутри тега <script type="text/javascript"></script>.

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

Определение своих типов:

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

Автор: metej

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js