Использование классов в JavaScript
Эмуляция классов в JavaScript
Библиотека дает писать код с возможностями классового программирования. В JavaScript нет классов, но есть прототипы. Собственно используя возможности языка, я попытался реализовать некую обертку, которая более или менее приближено показывает как можно использовать классовое программирование на языке JavaScript. Возможности библиотеки на мой взгляд вполне адекватны, поэтому при желании можно на ее основе построить огромный проект. Скорость работы кода с использованием данной библиотеки в целом не падает. Она старается максимально оптимизировать структуру классов. Библиотека работает во всех нынешних браузерах, даже в таком браузере как IE7, возможно даже в IE6 (Но я этого не проверял). Методы: Класс в текущем контексте Class(Object/Function classStructure) : FunctionКласс в указанном пространстве имен Class(String className, Object/Function classStructure) : FunctionКласc с наследованием Class([String className,] Function parent, Object/Function classStructure) : FunctionКласc с множественным наследованием Class(String className, String extends, Object/Function classStructure) : FunctionДругие вариации и методы Class([String className, ][Object options, ][Object/Function classStructure]) : FunctionИспользование:Все параметры являются не обязательными.Class.instanceOf( Object object, Function constructor ) : Boolean Использование библиотеки очень простое, и немногим схожа с объявлениями классов например в PHP Код в PHP:Как видите, сходство достаточно близкое. Я не стал придумывать что-то новое и попытался реализовать эмуляцию классов схожую к привычной в классовом программировании.class Foo { // структура класса }Код в JavaScriptClass( "Foo", { // структура класса }); Сейчас я немного расскажу о дополнительных параметрах, которые указываются в объекте options, описанный ранее в описании метода Class. Определение класса: Class("SimpleClass", { // свойства класса ... }); Конструкторы: конструкторы есть двух типов, первый это метод имеющий такое же имя как имя класса: Class("SimpleClass", { SimpleClass: function() { // будет вызван при создании экземпляра } });Второй вариант имеет всеми привычное имя: constructor, часто удобен при создании анонимных класов: var SimpleClass = Class({ constructor: function() { // будет вызван при создании экземпляра } }); ... описал бы больше, но тут лимит в 10000 символов на пост((( Типы и различия в файлах библиотек: class.js - Полная версия библиотеки, включает в себя все что описано выше. class.min.js - Сжатая с помощью GCC.Скачать все это можно на GitHub: https://github.com/devote/jsClasses |
не знал, что setter's/getter's можно реализовать для старых ie через vbscript, спасибо
|
Чтобы не было столько минусов, нужно было написать «В JAVASCRIPT НЕТ КЛАССОВ, НИЖЕ ИЗЛОЖЕН ОДИН ИЗ СПОСОБОВ ЭМУЛЯЦИИ»
|
Цитата:
Минусы как правило ставят те кто читал подобные статьи, но не удосужился прочесть эту. А просто включив опцию "стада" в голове пошел ставить минус. Уж таковы реалия и с этим ничего не поделаешь. PS. Писать статьи я не мастак, а точнее не писал никогда. От того и недопонимание у некоторых людей возникают. |
я обхожусь встроенными средствами. классы - на любителя.
Цитата:
devote, не поделитесь секретом ? |
Честно сказать, лучше бы сделал либу для поддержки какой-нибудь фигни из ES.next.
Цитата:
|
Цитата:
|
Цитата:
Цитата:
|
Цитата:
|
Цитата:
|
закинул на гитхаб совершенно новую реализацию, с исправлением множества багов, с добавлением доп возможностей по ходу понимания VBScript если кому надо качаем на гитхабе https://github.com/devote/jsClasses фоловится там не забываем
|
обновил версию
|
я конечно понимаю что всем похуй... но:
я снова обновил репу, добавил метод Class.imports теперь можно легко подгружать нужные модули: // синхронная загрузка Class.imports( "somescript.js" ); // синхронная мультизагрузка Class.imports( [ "somescript.js", "somescript2.js" ] ); // асинхронная загрузка Class.imports( "somescript.js", function() { // some code }); // асинхронная мультизагрузка Class.imports( [ "somescript.js", "somescript2.js" ], function() { // some code }); |
исправил еще один косячок, как выяснилось ИЕ ниже 9-й версии загружает и исполняет скрипты быстрее через XHR нежели через обычную вставку тега script на страницу. Остальные браузеры быстрее это делают через тег script.
Ну и добавил демо пример в первый топик. |
Цитата:
|
Цитата:
|
Цитата:
Вот здесь немножко передернуло: "Есть тут свои тонкости, конечно же нет возможности создания интерфейсов, абстракции и прочих полноценных прелестей ООП." |
Цитата:
Цитата:
|
Цитата:
|
Сначала удивился, а потом понял, что уже не помню насколько удобно использовать классы в native js, в частности наследование. По поводу __get/__set, можно проксировать методы/свойства (или агрегировать объекты). Например, у тебя есть коллекция, которая все неизвестные ей методы перенаправляет на свои элементы:
$$('.myClass').addEvent(...). |
Цитата:
|
Очередное обновление.
Немного оптимизирован код, исправлены пару мелких багов. Добавлены возможности. Теперь можно создавать классы любой вложенности, например: Class("ui.fx.Animation", { // ... })данный класс будет доступен как ui.fx.Animation, так же можно и расширять классы: Class("ui.Button extends ui.fx.Animation", { // ... })создастся класс ui.Button с унаследованными свойствами от ui.fx.Animation. Следующее нововведение это возможность объявлять классы совершенно в любом порядке. То-есть ранее нужно было учитывать порядок. Например нужно было перед объявлением класса ui.Button объявить класс ui.fx.Animation. Но теперь можно сначала объявить класс ui.Button а уже потом где-то ниже или подключить позже класс ui.fx.Animation, при этом все будет работать корректно. Наглядный пример: <script type="text/javascript" src="https://github.com/devote/jsClasses/raw/master/core.class.min.js"></script> <script> Class( "Foo extends Bar", { test: function() { return this.name; } }); Class( "Bar", { name: "Vasya" }); alert( (new Foo()).test() ); </script>Есть возможность отключить кеширование файлов при использовании Class.imports, достаточно где-то в начале кода установить значение: Class.imports.disableCaching = true;и все загружаемые файлы всегда будут вновь загружаться с сервера, это удобно для отладки кода. Так же можно перехватить ошибку загружаемого модуля, допустим при создании экземпляра класса не удалось найти класс от которого нужно наследоваться, в этом случае сработает событие Class.autoload, пример: <script type="text/javascript" src="https://github.com/devote/jsClasses/raw/master/core.class.min.js"></script> <script> Class( "Foo extends Bar", { test: function() { return this.name; } }); Class.autoload = function( className ) { alert( "Не найдет класс " + className + " в контексте " + this ); // тут можно вернуть конструктор другого класса например: return Class({ name: "Petya" }); // или же просто загрузить нужный класс, но в синхронном режиме // либо ничего не возвращать, что приведет к останову скрипта } alert( (new Foo()).test() ); </script>честно говоря над методом Class.autoload нужно еще поработать, мне конечно не совсем пока нравится как это работает. Поэтому в будущих версия этот метод возможно претерпит изменения. Так же забыл сообщить о том что при использовании метода Class.imports можно перехватить ошибку загрузки, пример: Class.imports([ "somefile.js", "somefile2.js" ], function(){ // succes loaded }, function( status, url ) { alert( "Ошибка загрузки файла: " + url + ", статус ошибки: " + status ); // если вернуть значение true, то загрузка остальных файлов продолжится не смотря на ошибку. // В противном случае загрузка файлов не будет продолжена. })насчет обработки ошибок тоже вполне возможно будут изменения, но пока не решил как улучшить и т.д. Если есть идеи/пожелания/критика, с удовольствием выслушаю. Спасибо. |
Цитата:
Цитата:
Class("ui.Button", { // ... }).extend(Class.ui.fx.Animation); Пожалусто :) |
Цитата:
Цитата:
Class("ui.Button extends ui.fx.Animation", { // ... });в этом случае класс лишь объявлен, и не имеет экземпляров, а вот когда мы вызываем: new ui.Button();в этом случае происходит наследование, то-есть вызывается создание экземпляра родительского класса. Не раньше. И если делать так как предлагаешь, то я понятия не имею как это реализовать. Хм... Хотя конечно мысль одна есть, попробую над ней подумать. |
B~Vladi,
да кстати я не упоминал наверно, но можно еще и так создавать классы: Class("ui.Button", ui.fx.Animation, { // ... });а вообще внутри библиотеки указаны примеры создания: /* * Class( context, "className", parentClass, staticObject, classStructure ) * Class( context, "className", parentClass, classStructure ) * Class( context, "className", staticObject, classStructure ) * Class( context, "className", classStructure ) * * Class( "className", parentClass, staticObject, classStructure ) * Class( "className", parentClass, classStructure ) * Class( "className", staticObject, classStructure ) * Class( "className", classStructure ) * * Class( parentClass, staticObject, classStructure ) * Class( parentClass, classStructure ) * Class( staticObject, classStructure ) * Class( classStructure ) */аж 12 вариантов: // первый параметр контекст в котором будет создан класс // второй имя класса // третий конструктор класса от которого хотим наследоваться // четвертый объект со статическими свойствами, которые будут доступны без создания экземпляра, через Foo.STATIC_PARAM // пятый, собственно сам класс Class( window, "Foo", Bar, { "STATIC_PARAM": "hello" }, { constructor: function() { } }); // все что выше но без статического объекта Class( window, "Foo", Bar, { constructor: function() { } }); // все что выше но без наследования, и со статическими параметрами Class( window, "Foo", { "STATIC_PARAM": "hello" }, { constructor: function() { } }); // все что выше но без наследования и без статических параметров Class( window, "Foo", { constructor: function() { } });остальное описывать не буду, по названиям должно быть понятно. |
Цитата:
Цитата:
Цитата:
|
Цитата:
|
Цитата:
На крайняк напиши JSDoc, адекватные IDE смогут подсказку показывать налету и не придется открывать исходники. |
Цитата:
|
Цитата:
JSDoc - версия JavaDoc для JS. Сайт проекта реализации на Java. В твоём случае нужно заменить комментарий на: /* * @name Создатель НАСТОЯЩИХ классов в JS!!11 0_o * @example * Class( context, "className", parentClass, staticObject, classStructure ) * Class( context, "className", parentClass, classStructure ) * Class( context, "className", staticObject, classStructure ) * Class( context, "className", classStructure ) * * Class( "className", parentClass, staticObject, classStructure ) * Class( "className", parentClass, classStructure ) * Class( "className", staticObject, classStructure ) * Class( "className", classStructure ) * * Class( parentClass, staticObject, classStructure ) * Class( parentClass, classStructure ) * Class( staticObject, classStructure ) * Class( classStructure ) */ В IDE от JetBrains доку можно смотреть по Ctrl+Q. Вот пример сгенерированной доки. |
B~Vladi,
вот спасибо добрый человек. Почитаю на досуге что к чему, я так понимаю IDE нужно для этого дела то.. Видимо придется поставить. |
Цитата:
|
а отлично, покумекаю над этим на досуге.. Доку то надо начирикать какую то.
|
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Class('MyClass', { myMethod: function() {...}, ... }, {context: '...', staticData: {...}}); т.е. такая сигнатура: Class(name, data, options) И по поводу extends/implements/include (наследование), их можно туда же засунуть. Или прямо в data, зарезервивовав для служебных целей, например, двойное подчеркивание: Class('MyClass', { __extends: 'MyBaseClass', __implements: 'MyMixin', __construct: function() {...}, myMethod: function() {...} }); |
Цитата:
|
Цитата:
Цитата:
Цитата:
Цитата:
При всем этом я писал из расчета скорости работы, если я напишу так как вы предлагаете во втором варианте, тоесть прямо в data это приведет к тому что при создании экземпляра нужно будет каждый раз разбирать все эти параметры, что приведет к занижению производительности. Хоть она и не заметна будет, но для большого кода/проектов это значительные потери. В моей же реализации, все манипуляции с параметрами происходят во время объявления класса, далее уже при создании экземпляров, никакие параметры не разбираются. Допустим: Class("Foo", Parent, { // вот именно в этот момент идет разбор параметров // some code }); // никакого разбора не происходит, но ищутся такие // свойства как setters/getters затем складываются в // специальный стек var a = new Foo(); // при втором обращении, уже ничего вообще не делается // а все сеттеры/геттеры берутся из стека, что увеличивает // скорость работы конструктора. var b = new Foo(); Цитата:
|
|
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 19:56. |