Разбираем AjaxOOP
Всем доброго времени суток.
Пересмотрев кучу библиотек для организации OOP на JavaScript более всего мне понравился синтаксис реализованный в библиотеке Ajax.OOP. Беда в том, что 1. Проект закрыт судя по всему 2. Файл содержит еще кучу всякой лабуду для Ajax, которая и даром не нужна. Посему решил понадергать кода оттуда что бы иметь маленькую библиотечку для OOP. Поскольку не считаю себя супер профессионалом в JS то прошу помощи у сообщества в сем деле. Предлагаю разбирать построчно анализировать код. Вообщем основная функция которая создает класс это Ajax.Class Предлагаю просто назвать ее _class код выкладываю далее ... |
чуть не забыл, понадобятся еще служебные функции.
в исходнике реализована функция $a которая используется по всей библиотеке. Нам интересна ее способность преобразовывать аргументы функции в массив. записал так function args2array(obj) { var al = obj.length; var args = new Array(al); while (al--) args[al] = obj[al]; return args; }; Еще есть функции проверяющие тип объекта. Реализация их не очень интересна, однако для чистоты эксперимента выкладываю код тоже Интерес вызывает isElement и isRegExp так как похоже для корректной работы потребуются дополнительные действия, но об этом позже. function isElement(obj) { return (obj && obj.nodeType && obj.nodeType == 1) ? true : false; }; function isRegExp(obj) { return (obj && obj.constructor === RegExp); }; function isString(obj) { return (typeof obj == 'string'); }; function isNumber(obj) { return (typeof obj == 'number'); }; function isBoolean(obj) { return (typeof obj == 'boolean'); }; function isNull(obj) { return (obj === null); }; function isUndefined(obj) { return (obj === 'undefined' || obj === undefined || obj === 'unknown'); }; function isArray(obj) { return (obj && obj.constructor === Array); }; function isSimple(obj) { return (isString(obj) || isNumber(obj) || isBoolean(obj) || isRegExp( obj)); }; function isFunction(obj) { return (obj && obj.constructor === Function); }; function isObject(obj) { return (obj && !(isArray( obj) || isFunction( obj) || isSimple( obj))); }; |
Для проверки на регэксп должно хватить
alert( /inline regexp/ instanceof RegExp ); alert( new RegExp('regexp') instanceof RegExp ); alert( '/not regexp+?/' instanceof RegExp ); |
И далее сама функция _class
//получаем массив аргументов var args = args2array(arguments); var al = args.length; // Если есть хотя бы 2 аргумента, значит первый это предок, запоминаем его и убираем из массива. Если предка нет, то он NULL var parent = (al > 1 ? args.shift() : null); // Получаем и запоминаем описание самого класса. Если такового нет, то пустое тело. Как и с предком убираем из массива аргументов тело класса. var declaration = (args.shift() || {}); // Типа конструктор ;-) var constructor = 'constructor'; // Проверяем правильный ли тип предка if (parent && !isFunction(parent)) { throw new TypeError( 'in class definition - first argument is not a parent class constructor!'); } // Проверяем является ли тело класса таковым if (declaration && (!isObject(declaration) || declaration == window || declaration == document.body || declaration == document || isElement(declaration))) { throw new TypeError( 'in class definition - ' + (args.length > 1 ? 'second' : 'passed') + ' argument is not a class declaration object!'); } // Собственно это и есть наш класс var _class = function() { this[constructor].apply(this, args2array(arguments)); } И тут начались проблемы с пониманием. apply - вызов функции с массивом параметров У свойства текущего контекста this[constructor] (фактически this['constructor']) вызывается (он сам по идее и вызывается) с передачей текущего контекста и оставшимися параметрами. Что зачем почему не понятно. // Пошло наследование свойств через прототип if (parent) { var _parent = Function.blank; _parent.prototype = parent.prototype; _class.prototype = new _parent; } 1. Содается переменная функция временая _parent ей присваивается пустая функция (она определена в другом месте как пустая) 2. Prototype этой временной функции присваивается prototype предка. 3. Prototype нового создаваемого класса становться вновь созданный экзампляр временной функции (которая имеет тот же prototype что и предок) // коли определены в текущем классе свойства, так соотвственно присвоить их, а коли они были в предке то переопределить. // ну хак с конструктором для IE if (declaration) { for (var property in declaration) { _class.prototype[property] = declaration[property]; } // line below is to fix bug with constructors in IE _class.prototype[constructor] = declaration[constructor] || Function.blank; } // этот кусок меня если четно не понятен. Особенно момент с возвратом прототипа пустой функции. Если честно не совсем понятно зачем создавать эти указатели на конструкторы .... _class.prototype.$super = parent ? parent.prototype : Function.blank.prototype; _class.prototype.$_super = parent ? parent : Function.blank; _class.prototype.$_self = _class; // собственно вернуть готовый класс return _class; Проанализировав код вдоль и поперек , не могу понять где тело конструктора мы присваиваем в _class Судя по всему в теле должны быть только свойства и методы определены, а код не допускается. ;-) Сложно выразился ... т.е. в теле любой код должен быть присвоением свойства или метода в синтаксисе someProp: 10, someMethod: function() {}, |
Цитата:
|
Может теорию сначала почитаете?
|
Цитата:
Цитата:
Если же все же это мне, то отвечу, читал я теорию и на этом сайте и на других, много и вдумчиво. Но поскольку нет идеологии или если хотите парадигмы ООП на JavaScript то вариантов много получается и почти все они построены на "хаках". |
Цитата:
|
eai, прежде чем что-то утверждать прочтите это.
Смею вас уверить, что ваша коробка транзисторов, резисторов, дросселей и емкостей полностью построена на, как вы выразились, "хаках". Для примера: многопоточность и многоядерность. Везде применяются те или иные методы обхода проблемных мест. |
Уф, я так и знал, что у меня будут сложности с пониманием в этом форуме. Ибо все же язык (общения) программиста на С++ всегда отличается людей которые работают на скриптовых языках. :)
Владлен, я не утверждал что нельзя использовать ООП на JS. Как вы можете заметить, я скорее наоборот всеми силами за. Однако как я заметил и заметили другие члены сообщества в разных местах в интернете, нет , как бы это яснее выразиться ..., нативной что ли возможности использовать это. Цитата:
Предлагаю не спорить по этому вопросу, так как вопроса в сущности то нет. |
eai,
не порите чушь. Считать википедию авторитетным источником, как минимум, глупо. В объектно-ориентированном программировании базовое понятие объект, а не класс. Я вас прекрасно понимаю, не вы первый, кто переходит с классовых языков на JavaScript. Но не надо быть таким упёртым, почитайте статьи на этом сайте, почитайте очень хорошие статьи Дмитрия Сошникова (раз, два), а потом уже беритесь делать очередной никому не нужный костыль, имитирующий классовое ООП там, где его нет и не надо. |
Коля
1. Я не порю чушь, так как это не я сослался на вики 2. В ООП важно не объект а наследование, полиформизм и.т.д Нельзя же считать "С" с его структурами ООП языком. 3. Я не перехожу на JavaScript я использую JavaScript. 4. И Раз и Два я читал, извините поиском умею пользоваться. 5. Давай те будем как то по корректнее! 6. не понимаю почему тема сводиться к перепалки без обсуждения сути вопроса |
Цитата:
Цитата:
Цитата:
|
Цитата:
Мешает то что, что надо делать так var F = function() { } F.prototype = Parent.prototype Child.prototype = new F() Child.prototype.constructor = Child Child.superclass = Parent.prototype и еще по всякому и еще, я не говорю что JS плохой там или еще как. Просто он иной нежели например C++. И я пытаюсь использовать JS с принципами построения приложений ООП и не более. Всю тему я поднял, только для того что бы убедиться что я на верном или не верном пути проводя реинжениринг кода из AjaxOOP. |
Цитата:
Цитата:
Цитата:
Мне, например, по всем критериям хватает для организации наследования функции на 10 строк. /** * Создаёт конструктор, прототип которого наследует прототип текущего конструктора. * Для создания ничего не наследующего конструктора следует использовать Object.inherit({...}). * @param {Object} proto Объект с методами и свойствами, копирующимися в прототип создаваемого конструктора. * @return {Function} Созданный конструктор. */ Function.prototype.inherit = function(proto) { var that = this; proto = proto || {}; var constructor = proto.hasOwnProperty('constructor') ? proto.constructor : function() { that.apply(this, arguments); }; var F = function() {}; F.prototype = this.prototype; constructor.prototype = apply(new F(), proto); constructor.superclass = this.prototype; constructor.prototype.constructor = constructor; return constructor; };Она не добавляет никаких новых сущностей в язык, она просто упрощает создание и наследование конструкторов. |
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
function apply(dst) { for (var i = 1; i < arguments.length; i++) { for (var prop in arguments[i]) { if (arguments[i].hasOwnProperty(prop)) { dst[prop] = arguments[i][prop]; } } } return dst; } Function.prototype.inherit = function(proto) { var that = this; proto = proto || {}; var constructor = proto.hasOwnProperty('constructor') ? proto.constructor : function() { that.apply(this, arguments); }; var F = function() {}; F.prototype = this.prototype; constructor.prototype = apply(new F(), proto); constructor.superclass = this.prototype; constructor.prototype.constructor = constructor; return constructor; }; var A = Object.inherit({ constructor: function(a) { this.a = a; }, method: function() { alert(this.a); } }); var B = A.inherit({ constructor: function() { B.superclass.constructor.apply(this, arguments); this.a++; } }); var a = new A(5); var b = new B(5); a.method(); b.method(); |
Беру таймот на разбор :-)
Спасибо P.S. Обдумал выпад на счет C++. Да я хочу статическую классовую модель, а поскольку это низя, то хочу максимально приближенное. |
а Алан Кей думал по-другому :blink:
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." The big idea is "messaging" -- that is what the kernal of Smalltalk/Squeak is all about (and it's something that was never quite completed in our Xerox PARC phase). The Japanese have a small word -- ma -- for "that which is in between" -- perhaps the nearest English equivalent is "interstitial". http://www.c2.com/cgi/wiki?AlanKayOnObjects |
А мне страуструп ближе
|
И так разбор библиотечки Коли.
Создание объектов до отказа браузера. Результат хороший. Хром(лучший результат) создал 17 миллионов объектов. При этом увеличение количества методов не повлияло на результат. Вывод, тело методов не плодиться для каждого экземпляра в отдельности. И это правильно товарищи :) |
Создаем объекты без наследования (от Object не считается)
var Point = Object.inherit({ x: 0, // что то вроде значения по умолчанию y: 0, // что то вроде значения по умолчанию constructor: function(ax,ay) { this.x = ax; this.y = ay; }, toString: function(){ return "(x=" + this.x + " y=" + this.y + ")"; } }); Работает! Вообще если уж сравнивать с C++ то присвоение свойств объекта в момент объявления это не есть правильно. Однако это полезная фича (на мой взгляд), тем более что у нас ситуация когда присваивание и есть объявление. Так мы имеем возможность присваивать значение свойств по умолчанию. Усложняем var Point = Object.inherit({ a: new Array(2), constructor: function(ax,ay) { this.a[0] = ax; this.a[1] = ay; } }); Не работает. Вернее работает, но свойство а ведет себя как статическое свойство. Иными словами оно общее для всех экземпляров "класса" Point. Посему заповедь. Хочешь свойство сложного типа, создавай его в конструкторе. var Point = Object.inherit({ a: null, //вообще без этой строчки можно обойтись, но выглядит красивым объявлением constructor: function(ax,ay) { this.a = new Array(2); this.a[0] = ax; this.a[1] = ay; } }); Кстати, а можно ли с помощью этой библиотеки создавать статические свойства простых типов? |
Цитата:
Цитата:
|
Типа так
Point.someProperty = ' I am static property'? Завтра начну тестировать наследование и перегрузку методов. |
Да.
|
Цитата:
function apply(dst) { for (var i = 1; i < arguments.length; i++) { for (var prop in arguments[i]) { if (arguments[i].hasOwnProperty(prop)) { dst[prop] = arguments[i][prop]; } } } return dst; } Function.prototype.inherit = function(proto) { var that = this; proto = proto || {}; var constructor = proto.hasOwnProperty('constructor') ? proto.constructor : function() { that.apply(this, arguments); }; var F = function() {}; F.prototype = this.prototype; constructor.prototype = apply(new F(), proto); constructor.superclass = this.prototype; constructor.prototype.constructor = constructor; return constructor; }; var Point = Object.inherit({ a: new Array(2), constructor: function(ax,ay) { this.a[0] = ax; this.a[1] = ay; } }); // --- var a = new Point(1, 2); var b = new Point(3, 4); alert(a.a.concat(b.a)); a.a = [5, 6]; alert(a.a.concat(b.a)); |
кстати, неплохая статья по теме
http://rainman-rocks.livejournal.com/67138.html в частности, "динамические системы программирования созданы для иных целей, нежли статические, и не должны пытаться копировать подходы статических систем" или не надо писать на javascript, как будто это C++. Ничего хорошего не получится ;) |
Так сказать из уст пионера в поисках истины ООП в JavaScript
Classical Inheritance in JavaScript Prototypal Inheritance in JavaScript Private Members in JavaScript |
Цитата:
PHP и Perl устроены иначе, поэтому (и не только поэтому) они - плохие языки Плохой язык не тот который поэтому (и не только по этому) а тот который не соответствует следующему выводу в той же статье разработка на динамических языках должна быть более ориентирована на решение практических задач, чем на построение сложной архитектуры приложения Но тут я бы убрал "построение сложной архитектуры", ибо архитектура не цель а средство! многослойные городушки из классов - строго противопоказаны динамическим языкам Таки товарищЬ утверждает что ООП не приемлимо в JS? Ай-ай-ай Я бы сделал вывод что rainman_rocks чиста WEBщик (кстати по сему видно что вумный) но не видит перед собой уже начавшийся революции перевода больших стационарных приложений на WEB (облако). Ну низя без архитектуры большое приложение разрабатывать и поддерживать. Вот он утверждает что "придется тщательно обучить остальных разработчиков, работающих над проектом". А как вы еще хотели проект делать? Признать честно я вырвал это из контекста перегрузки операторов. А вот перегрузка операторов по моему мнению это крайняя мера! Вообщем чел вумный но не туда гребет. |
Цитата:
|
Хм, товарищ использовал класс как универсальное понятие для описание объектов. Ключевой смысл в его фразе "многослойные городушки"
ну и Николай, не выли писали "В объектно-ориентированном программировании базовое понятие объект, а не класс." ;-) |
Цитата:
Цитата:
|
Цитата:
Цитата:
Николай, если вы в Питере то предлагаю купить бутылку водки :) и ... выпить ее :) |
Цитата:
Цитата:
Но я не в Питере :) |
Цитата:
Жаль что не в Питере, а то посидели бы ;-) А чтоб похмелье не было закусывать надо хорошо :) |
Цитата:
В javascript: объекты есть, наследование есть, классов нет. |
Хорошо, тогда скажу так
Я считаю целесообразным по необходимости городить многослойные объектные структуры. ВОТ! |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
1. Повторное использования кода 2. Управления объектами 3. Управления поведением объектов 4. Принцип абстракции это что дает, можно конечно возразить, что можно мол и без ООП, но тогда синтаксис выходит сложный, не прозрачный что ли. Вообще наследование призвано отразить иерархичность реального мира. |
Цитата:
Цитата:
Цитата:
mixin(Obj, Observable); а наследование провоцирует спихивание общей функциональности вверх по иерархии, в результате чего, чтобы узнать, что делает метод надо лазить по этой иерархии вверх-вниз и обратно. При агрегации это не так актуально, так как наследование - более тесная связь, т.е. оно увеличивает связанность (coupling), что есть не хорошо, особенно для "больших стационарных приложений" ;) Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Можно еще Александра Степанова вспомнить (разработчик STL если чё) Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 07:17. |