Первый топик постигла участь многих пятничных постов, но не беда!
Я не сдаюсь, а значит мы продолжаем…
В этом топике мы осветим следующие темы:
- Классы. Определение, создание экземпляров, наследование.
- Методы и поля классов, конструкторы и методы базового класса
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