Jin: И снова о наследовании
Зацените крутую либу реализующую новый подход к организации кода)
Фичи: 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 Как видно доступ к перегруженным методам возможен через их полные имена. Указание перегружаемых методов для каждого перегружающего метода может показаться избыточным, однако перегрузка на уровне классов не может выявить конфликты при появлении новых методов в них. Поэтому такая перегрузка и не предусмотрена. Багрепорты и идеи приветствуются) |
Забыл саму либу)
this.$jin = {} $jin.value = function $jin_value( value ){ var func = function $jin_value_instance( ){ return func.$jin_value } func.$jin_value = value return func } $jin.root = $jin.value( this ) $jin.glob = function $jin_glob( name, value ){ var keyList = name.split( '_' ) var current = $jin.root() var currentName = '' while( keyList.length > 1 ){ var key = keyList.shift() || 'prototype' currentName += ( currentName ? '_' : '' ) + ( key === 'prototype' ? '' : key ) if(!( key in current )){ current[ key ] = $jin.trait.make( currentName ) } current = current[ key ] } var key = keyList.shift() || 'prototype' if( arguments.length > 1 ){ current[ key ] = value } else { value = current[ key ] } return value } $jin.lazy = function $jin_lazy( generator ){ if( typeof generator === 'string' ){ generator = $jin.lazy.glob( generator ) } var lazy = function $jin_lazy_instance( ){ return lazy.$jin_lazy_func.apply( this, arguments ) } lazy.$jin_lazy_gen = generator lazy.$jin_lazy_func = function $jin_lazy_generate( ){ var func = lazy.$jin_lazy_func = lazy.$jin_lazy_gen() return func.apply( this, arguments ) } return lazy } $jin.lazy.glob = function $jin_lazy_glob( name ){ var lazy = function $jin_lazy_glob( ){ return $jin.glob( lazy.$jin_lazy_name ) } lazy.$jin_lazy_name = name return lazy } $jin.trait = function $jin_trait( name ){ var trait = $jin.glob( name ) if( trait ) return trait trait = $jin.trait.make( name ) return $jin.glob( name, trait ) } $jin.trait.make = function $jin_trait_make( name ){ eval( 'var trait= function ' + name + '( ){ \ return ( this instanceof trait ) ? this : trait.apply( trait, arguments ) \ }' ) trait.name = name trait.apply = void 0 trait.prototype = {} return trait } $jin.method = function $jin_method( ){ // arguments: resolveName*, func var resolveList = [].slice.call( arguments ) var func = resolveList.pop() var name = func.name = func.name || func.toString().match( /^\s*function\s*([$\w]*)\s*\(/ )[ 1 ] if( !name ) throw new Error( 'Can not register anonymous function' ) func.$jin_method_name = func.$jin_method_name || name func.$jin_method_resolveList = resolveList.concat( func.$jin_method_resolveList || [] ) $jin.method.define( name, func ) } $jin.method.define = function $jin_method_define( name, func ){ var funcName = func.$jin_method_name if( !funcName ) throw new Error( '$jin_method_name is not defined in [' + func + ']' ) var nameList = name.split( '_' ) var methodName = nameList.pop() var ownerPath = nameList.join( '_' ) var owner = $jin.trait( ownerPath ) owner[ funcName ]= func var existFunc = owner[ methodName ] checkConflict: { if( existFunc === void 0 ) break checkConflict if( typeof existFunc !== 'function' ){ throw new Error( 'Can not redefine [' + existFunc + '] by [' + funcName + ']' ) } if( func === existFunc ) return existFunc if( !existFunc.$jin_method_name ) break checkConflict func = $jin.method.merge( existFunc, func, name ) } owner[ methodName ]= func var slaveList = owner.$jin_mixin_slaveList if( slaveList ) slaveList.forEach( function( slavePath ){ $jin.method.define( slavePath + '_' + methodName, func ) }) return func } $jin.method.merge = function $jin_method_merge( left, right, name ){ var leftConflicts = left.$jin_method_conflictList || [ left ] var rightConflicts = right.$jin_method_conflictList || [ right ] var conflictList = leftConflicts.concat( rightConflicts ) var leftResolves = left.$jin_method_resolveList || [] var rightResolves = right.$jin_method_resolveList || [] var resolveList = leftResolves.concat( rightResolves ) conflictList = conflictList.filter( function( conflict ){ return !~resolveList.indexOf( conflict.$jin_method_name ) }) if( conflictList.length === 0 ){ throw new Error( 'Can not resolve conflict ' + name + ' because cyrcullar resolving' ) } else if( conflictList.length === 1 ){ var func = conflictList[0] } else if( conflictList.length > 1 ){ eval( 'var func= function ' + name + '( ){ \ throw new Error( "Conflict in [" + func.$jin_method_name + "] by [" + func.$jin_method_conflictList + "]" )\ }' ) func.$jin_method_name = name func.$jin_method_conflictList = conflictList } func.$jin_method_resolveList = resolveList return func } $jin.method.naming = function $jin_method_naming( name, owner ){ if( arguments.length < 2 ){ owner = $jin.glob( name ) } for( var key in owner ){ if( !owner.hasOwnProperty( key ) ) continue var value = owner[ key ] if( Object( value ) !== value ) continue $jin.method.naming( name + '_' + key, value ) } if( typeof owner === 'function' && !owner.$jin_method_name ){ $jin.method.naming( name + '_', owner.prototype ) owner.$jin_method_name = name owner.$jin_method_resolveList = [ '$jin_klass__constructor' ] } } $jin.mixin = function( ){ // arguments: sourceName+, targetName var trait = $jin.mixin.object.apply( this, arguments ) for( var index = 0; index < arguments.length; ++index ){ arguments[ index ] += '_' } $jin.mixin.object.apply( this, arguments ) return trait } $jin.mixin.object = function( ){ // arguments: sourceName+, targetName var sourcePathList = [].slice.call( arguments ) var targetPath = sourcePathList.pop() var target = $jin.trait( targetPath ) sourcePathList.forEach( function( sourcePath ){ var source = $jin.trait( sourcePath ) source.$jin_mixin_slaveList = source.$jin_mixin_slaveList || [] if( ~source.$jin_mixin_slaveList.indexOf( targetPath ) ) return source.$jin_mixin_slaveList.push( targetPath ) for( var key in source ){ var func = source[ key ] if( typeof func !== 'function' ) continue if( !func.$jin_method_name ) continue $jin.method.define( targetPath + '_' + key, func ) } if( source.constructor && source.constructor.$jin_method_name ){ $jin.method.define( targetPath + '_constructor', source.constructor ) } }) return target } $jin.property = function $jin_property( ){ // arguments: resolveName*, name, type var resolveList = [].slice.call( arguments ) var type = resolveList.pop() var name = resolveList.pop() var fieldName = '_' + name eval( 'var property = function ' + name + '( ){ \ return property.apply( this, arguments ) \ }' ) property.name = name property.apply = function $jin_property_apply( obj, args ){ if( args.length ){ obj[ fieldName ] = property.$jin_property_ensureType( args[ 0 ] ) return obj } else { if( obj.hasOwnProperty( fieldName ) ){ return obj[ fieldName ] } else { return obj[ fieldName ] = property.$jin_property_ensureType() } } } if( typeof type === 'string' ) type = $jin.lazy.glob( type ) property.$jin_property_ensureType = type || function( value ){ return nvalue } property.$jin_method_resolveList = resolveList return $jin.method( property ) } $jin.klass = function $jin_klass( ){ // arguments: sourceName*, targetName $jin.mixin.apply( this, arguments ) var name = arguments[ arguments.length - 1 ] return $jin.mixin( '$jin_klass', name ) } $jin.method( function $jin_klass_apply( klass, args ){ var obj = new klass obj.constructor.apply( obj, args ) return obj } ) $jin.method( function $jin_klass_toString( ){ return this.name } ) $jin.method( function $jin_klass__constructor( config ){ if( !config ) return this for( var key in config ){ this[ key ]( config[ key ] ) } return this } ) |
Цитата:
|
$имяПакета_имяМодуля_уника� �ьноеИмяВРамкахМодуля
|
Парсер лох, чо)
|
Хотя, тут можно и точку наверно использовать в качестве разделителя. Более существенные замечания будут?)
|
О, вспомнил! Надо твою статью про
yield перечитать до полного понимания. :) |
Она-то тут при чём? о_0" Да и не сильно она актуальна уже.. либу я ту переписал по другому.
|
Не при чем) Читал, когда в армии был. Что-то не найду ссылку. Там где пошагово расписывает про волокна. Еще осталась эта статья?
|
|
Часовой пояс GMT +3, время: 09:30. |