Зацените крутую либу реализующую новый подход к организации кода)
Фичи:
1. множественное виртуальное наследование
2. прямой быстрый доступ к любому методу предка
3. автоматическое объявление классов и пространств имён
4. объявление методов и примешивание в произвольном порядке
5. автоматическое выявление конфликтов на уровне методов
6. типизированные свойства
7. глобально именуемые функции
Объявим простенький синглтон:
$jin.method( function URI_encode( text ){
return encodeURIComponent( text )
})
$jin.method( function URI_decode( text ){
return decodeURIComponent( text )
})
Данный код примерно эквивалентен следующему:
var URI = URI || {}
URI.encode = function URI_encode( text ){
return encodeURIComponent( text )
}
URI.decode = function URI_decode( text ){
return decodeURIComponent( text )
}
Как видно, мы избавились от необходимости дублировать имя функции при объявлении (что полезно при дебаге, но зачастую лениво), а также не беспокоимся о том, чтобы нужный неймспейс существовал до объявления методов. Символ подчёркивания, как видно, заменяется на точку. Кроме того двойное подчёркивание заменяется на ".prototype.", что будет продемонстрировано ниже.
Теперь создадим простейший класс:
$jin.mixin( '$jin_klass', 'Man' )
$jin.property( 'Man__name', String )
Тут мы примешали к пространству имён Man поведение "$jin_klass", что превращает "Man" в фабрику объектов. После чего определяем свойство "name", которое всегда является строкой. Инстанцирование происходит простым вызовом:
var Anonymous = Man()
При этом можно передать хэш со значениями свойств:
var John = Man({ name: 'John' })
Попытка передать значение для несуществующего свойства приведёт к ошибке, так как соответствующая функция не будет найдена.
Man({ age: 17 }) // Error!
Свойства - всего-лишь функции, которые в зависимости от числа переданных параметров либо возвращают своё значение, либо устанавливают.
Man().name( 'Bob' ).name() // 'Bob'
При установке значения переданный параметр прогоняется через "типа свойства" - функцию, которую мы передали вторым параметром при создании свойства.
Man().name( 17 ).name() // '17' потому что String( 17 )
Если значение ещё не установлено, то функция типа вызывается без параметров, чтобы сгенерировать дефолтное значение.
Man().name() // '' потому что String()
Разумеется можно определять различные свои типы.
Наследование реализуется через примешивание:
$jin.property( 'Artist__sceneName', String )
$jin.mixin( '$jin_klass', 'Artist', 'Man' )
Man().sceneName() // ''
Примешивать и создавать методы можно опять же в произвольном порядке.
$jin.mixin( 'Artist', '$jin_klass', 'Man' )
$jin.property( 'Artist__pseudoName', String )
Man().sceneName() // ''
Чтобы каждый раз не примешивать $jin_class можно сразу его и вызывать:
$jin.class( 'Artist', 'Man' )
Иногда могут возникать конфликты имён:
$jin.property( 'Artist__name', String )
$jin.klass( 'Artist', 'Man' )
$jin.property( 'Man__name', String )
Man().name() // Error!
Чтобы решить его нужно явно указать, что один метод может перегружать другой, посредством добавления дополнительного параметра вначале (коих может быть и несколько):
$jin.property( 'Artist__name', String )
$jin.klass( 'Artist', 'Man' )
$jin.property( 'Artist__name', 'Man__name', String )
Man().name() // ''
Тут мы указали, что в случае конфликта между "Artist__name" и "Man__name" использовано будет последнее. $jin.method действует аналогично.
$jin.method( function Man__toString( ){
return 'Man'
})
$jin.method( function Black__toString( ){
return 'Black'
})
$jin.klass( 'Man', 'Black', 'ManInBlack' )
$jin.method( 'Man__toString', 'Black__toString', function ManInBlack__toString( ){
return this.Man__toString() + ' in ' + this.Black__toString()
})
ManInBlack() + '' // Man in Black
Как видно доступ к перегруженным методам возможен через их полные имена.
Указание перегружаемых методов для каждого перегружающего метода может показаться избыточным, однако перегрузка на уровне классов не может выявить конфликты при появлении новых методов в них. Поэтому такая перегрузка и не предусмотрена.
Багрепорты и идеи приветствуются)