Переход от классического программирования к объектно-ориентированному давно провозглашен, но до сих пор не завершен, а все современные языки программирования уже давно имеют собственные объектно-ориентированные концепции и синтаксис.
О различиях, стеке и рекурсии
Различия между реализациями объектно-ориентированной доктрины языками программирования, разница в их философии и понимании новой логики их авторами и разработчиками велика.
Уровень стековой организации данных и уровень рекурсии современных алгоритмов в области интернет-программирования низки и не часто встречаются. Локальное программирование применяет стек и рекурсию только при явной необходимости или при прямом указании задания на разработку.
Эти обстоятельства говорят о том, что динамика переменной и динамика набора значений (массив) в процессе исполнения алгоритма находятся на «начальном» уровне развития представлений о данных и алгоритмах.
Возможно, это не так, а мир интернет-программирования стремительно развивается.
Если переменная (в том числе в статусе массива или объекта) - это стек, то появляется история значений и возможность перемещаться по ней в поисках нужной информации (значения) или оптимального решения (множества значений).
Если функция (алгоритм) представляет собой последовательность действий без рекурсии (без возможности вызвать саму себя) - это тупик, который не может развиваться без сторонней помощи (без участия программиста).
Даже если цель функции не развитие своей функциональности, но функция рекурсивна, она может претендовать на статус полнофункционального решения, а это важно, это уровень программирования и оценка квалификации программиста.
Переменная, ее значение и место в алгоритме
Расстояние между переменной и массивом ничтожно на линии развития программирования.
Переменные моментально стали привычными и сразу привели к созданию различных структур данных. Появились массивы, структуры, записи и другие конструкции первых языков программирования.
Когда властвовал Фортран и Бэйсик, об объектах еще даже не мечтали, а классический синтаксис оператора - это была отдельная строчка кода.Только в исключительных случаях можно было писать в одной строчке пару операторов.
Массивы появились быстро, но до сих пор нет понимания переменной как места в алгоритме, то есть момента изменения ее значения и понятия истории этих моментов.
Понятие «отката» - прерогатива прикладных программ. Операционные системы и языки программирования никогда не брали во внимание целесообразность и важность истории действий (событий) и право программиста/пользователя на их отмену.
До сих пор понятие истории действий и возможности движения по ней (undo и redo) не признается «ведущими» авторитетами переднего края информационных технологий, но насколько это хорошо и правильно?
Право на отмену решения, изменение поведения, поиска оптимального решения из принятых:
- естественное право человека (как программиста, так и пользователя);
- объективная функциональность любого приложения, любой части программного кода.
Пора понять и признать это изготовителям операционных систем и инструментальных средств программирования.
Переменная или массив - это не одно значение или одно множество значений, это всегда история значений и ее динамика даже, если это объективное обстоятельство не используется программистом сознательно. Если было бы иначе, отладке подвергался бы и код, и история изменения значений переменных, массивов и объектов - это совсем другой уровень надежности результата работы программиста. Это отладчик, работающий на уровне динамики активного функционала, а не конкретной позиции в статичном коде.
Язык браузера, его массивы и объекты
Теория программирования не так востребована, как практика программирования на JavaScript. Это обычное положение вещей. Страница, попавшая в браузер, моментально расписывается на дерево DOM и становится источником данных в виде:
- переменных;
- массивов;
- объектов.
Составляя скрипт, программист использует имеющиеся массивы JS, создает собственные массивы, описывает временные переменные и разрабатывает эффективные объекты интерфейса, данных и диалога с посетителем.
Места для истории значений и решений здесь нет, времени на проектирование историй изменений переменных и массивов тоже нет, а для объектов - это делается по мере необходимости.
Результат: веб-ресурс в редких случаях предоставляет «откат», а понятие истории уже «давно есть» в меню браузера в контексте движения по истории страниц: вперед, назад или выбор из списка.
Понятие истории значений на уровне переменных оказывается не востребованным. В стеке и рекурсии - нет надобности, если это явно не вытекает из сути задачи или проектируемого алгоритма.
Привет, переменная, когда ты массив
С давних пор обучение программированию начиналось с описания простой переменной «i am variable!» и вывода ее значения «Hello, World!!».
В данном примере, ничто не мешает массивы JS превратить в переменную с одним значением, а переменную i_am_VARIABLE сделать массивом.
Есть существенная разница между «[ ... ]» и «{ ... }», но нет никакой разницы между aSimple и oSimple. Любая переменная может поменять свой тип в любом месте алгоритма и в любое время.
HTML-элементы страницы, загруженной в браузер, насыщены событиями, большинство из которых разработчик отслеживает и назначает им нужный функционал в JavaScript-коде. Функции JS, вызываемые по событиям на элементах DOM, могут менять массивы JS в любой момент времени. Это дает шанс формировать историю, но этим мало кто пользуется.
Особенности описаний массивов и объектов
Реализация объектно-ориентированного программирования (ООП) в JavaScript - лучшая, на том простом основании, что это язык браузера всегда работает на реальных объектах. Несмотря на то, что реальными объектами являются объекты страницы, преобразованной в DOM, эти объекты управляются функционалом страницы и действиями посетителя. А это опыт JS и работа с массивами, как с реальными данными.
В приведенном примере заполнение переменной aSimple (на самом деле это массив) происходит только тремя операторами, и получается набор из трех значений: "Фортран", "Алгол" и "Basic". JS, как ассоциативные массивы, не интерпретирует описание переменной квадратными скобками.
Напротив, любая попытка использовать переменную иначе, чем описано фигурными скобками, обречена на провал. В описании объектов важны также используемые кавычки и кодировка. Если в перспективе массив или объект будут использованы в формате JSON, потребуется кодировка UTF-8 и только двойные кавычки.
Если к переменной применено описание «{ ... }», значит, это динамический массив с текстовыми ключами, возможно, полноценный объект с методами и собственной структурой данных.
Стек внутри массива
Массив - это множество значений. Количество технически не ограничено, но использовать большие объемы данных не целесообразно. Элементом массива может быть другой массив. Сам массив - это простая форма объекта. Создавать многомерные массивы допустимо, но большое количество размерностей может усложнить решение задачи.
Объем массива и количество размерностей в нем должны лежать в разумных пределах. Это упрощает разработку алгоритма и его развитие.
JavaScript не навязывает программисту стек и не требует обязательной рекурсивности от функций программиста. Мир задач и решений слишком сложен, чтобы навязывать что-либо синтаксисом языка, но инструменты для построения стека в JS исполнены в полном объеме.
Классические методы push и pop могут быть применены к любой переменной, описанной посредством «[ ... ]», и это будет динамический массив. Количество элементов в нем увеличивается по методу push, а при извлечении элемента методом pop «активным» становится последний элемент.
Результат метода pop - последний элемент массива, потому следующим при применении pop будет следующий предыдущий элемент массива. При добавлении элемента методом push он приходит следующим за последним.
Манипулируя вызовами push и pop, программист получает стек. Если в стек приходят/уходят массивы JS - это динамика (история) наборов значений или решений.
Обратная стопка тарелок: массив в строку
Стек всегда сравнивали со стопкой тарелок: каждая новая тарелка ложится только сверху и брать можно только сверху. Всегда доступна только верхняя тарелка (метод pop) или место над ней (метод push).
JavaScript расширил эту парадигму и предоставил возможность работы со стопкой тарелок как в классическом варианте, так и в обратном: программист может рассматривать начало стопки тарелок как стек через первый элемент. Методы shift и unshift аналогичны pop и push, но работают с первым элементом.
Массив - это набор значений, а методы join и split - это связь массива со строкой. Грань между массивом и переменной отсутствует. Следующий пример показывает это.
Изначально был описан массив aSimple типа «[ ... ]», и у него были реальные три значения. Затем aSimple обратился в переменную - строку символов. Затем в aSimple были записаны три элемента, которые методом join превратились в одну строку, а по методу split - создали новый массив aStr, без использования описания «[ ... ]».
Реальный стек от дерева DOM
Стек - это не всегда массив, который устроен привычным образом. Объекты - это не всегда методы, обеспечивающие доступ к содержанию объекта, но элементы дерева DOM всегда служат источником событий, которые обрабатывает набор функций на JavaScript.
Если представить все потенциальные источники события одним временным срезом в момент возникновения хотя бы одного события, то:
- может возникнуть только одно событие;
- может возникнуть два или несколько событий;
- возможно посещение этой же страницы другим или несколькими посетителями;
- возможно обращение сервера к клиенту, то есть к браузеру;
- допустима активность AJAX процесса;
- возможно, запущен один или несколько таймеров.
Это реальный стек событий серьезного сайта. Реализовать его в качестве массивов или объектов практически невозможно. Это совершенно иной уровень программирования, при котором статичный код, тела функций и методов имеют существенное значение, но ни отладить, ни отследить какой-либо процесс невозможно, если нет четкого представления о состоянии и динамике всей картины.
Проблема ООП и преимущество классического программирования в том-то и состоит, что реальное объектно-ориентированное программирование рекурсивно запускает массу объектов, которые взаимосвязаны друг с другом и могут запускать экземпляры уже работающих (запущенных каким-либо другим объектом или самим собой) объектов.
Разобрать, какой именно экземпляр функционирует по коду функции или метода, нельзя. Код - это статика, а какой именно экземпляр активен - динамика. Активная точка пространства - это статичный код, но уровень рекурсии и состояние актуальных данных - реальная проблема.
Реальный объектно-ориентированный проект
Практичный и востребованный JS объект получается для управления проектом PHPOffice/PHPWord. Эта библиотека содержит множество PHP объектов, работающих на стороне сервера. Большинство объектов реализует свойства объектов текстового процессора MS Word и предназначены для чтения и формирования *.docx файлов.
Библиотека не включает в себя JS объект для управления процессом формирования файла результата, но включает в себя уникальный пример взаимосвязанной системы объектов.
Любой абзац *.docx файла может содержать в себе несколько шрифтов, начертаний, цветов, подстрочные и надстрочные индексы. Современное оформление текста использует множество приемов и позволяет формировать уникальные по содержанию и оформлению документы.
Любой абзац *.docx файла может быть таблицей. В таблице может быть множество колонок и строк, но создать многомерные массивы по строкам или столбцам не получится. Уникальный объект - ячейка, которых может быть сколько угодно в строке или колонке.
Если привязаться к ячейке, то в ней может быть любое количество абзацев. В каждом абзаце может быть любое форматирование, которое допустимо при форматировании каждого абзаца основного текста.
Любой абзац в ячейке может быть таблицей, со всеми выше обозначенными возможностями! Библиотека PHPOffice/PHPWord - уникальный пример рекурсии и стековой организации данных. Возможно, разработчики MS Word используют свои специфические наработки в области программирования, но на JS: массив объектов, рекурсивно создающий таблицу таблиц, позволяющий иметь сколь угодно абзацев, таблиц, вложений друг в друга - реальность, реализуемая более эффективно, чем PHP вариант.
Проблемы рекурсии и стека: объектно-ориентированное мышление
Абзац содержит предложения, фразы, слова и объекты. Любая текстовая часть абзаца может иметь жирное, наклонное или подчеркнутое начертание. В любом месте текста может быть надстрочный индекс или изменен цвет букв.
Объект абзаца должен допускать рекурсию по вариантам начертания, но абзац нельзя вложить друг в друга. Можно вложить таблицу в абзац. В таблице может быть множество ячеек, а в каждой из них множество абзацев и множество таблиц.
Создание объектов по свойствам текста:
- жирность;
- наклон;
- подчеркивание;
- перечеркивание;
- изменение цвета;
- надстрочный индекс;
- подстрочный индекс;
- и др. -
приводит к объектам форматирования. При удалении элементов абзаца на самом деле элементы не удаляются. MS Word предусматривает возможность отката, то есть восстановления удаленного элемента. История undo/redo в текстовых процессорах - это норма вещей. Этого нельзя сказать про JS: удалить элемент массива - значит потерять его, если не предусмотреть собственный вариант отката.
Объект абзаца не может включать в себя объекты предложений, фраз или слов. Это избыточно, не современно и позволит построить стройную систему объектов *.docx- документа.
Таблица - самостоятельный объект, но тесно связанный с объектом абзаца. Эти два объекта могут вызывать друг друга взаимно, и уровень вложенности таких вызовов не ограничен. Здесь возникает проблема уровня, на котором мыслит программист или работает отладчик.
Сформулировать очередное решение или найти ошибку очень трудно, если мыслить классическим образом на уровне кода. Но если иметь представление о динамике данных и текущем уровне вложенности вызовов (стеке), то легко можно двигаться дальше, обнаруживая по ходу разработки, баги, неопределенности и слабые места.
Идеальный фундамент для организации стека - JS строка, не обязательно в формате JSON, удобном для обмена между сервером и клиентом. Трансформируя серверный компонент - библиотеку PHPOffice/PHPWord - в последовательность AJAX запросов, можно получить читабельный вариант «движения» по реальному документу.
Фактически, функционал библиотеки разобрал документ и сложил систему объектов, но просматривать его можно в браузере и строить адекватную динамичную систему объектов.
На JS добавить в массив последовательность строк - не проблема. Протокол рекурсивных уровней будет доступен, логика перемещения по уровням вложенности - очевидна. Возможно создать историю перемещений по значениям переменных, массивов, коду методов объектов и функциям.
Рекурсия в системе разных объектов
Объекты и массивы в JavaScript - всегда хорошее решение. Проекты класса PHPOffice/PHPWord - всегда хороший серверный вариант приложения. Есть разница между программированием на PHP и программированием в среде браузера.
Объект браузера «живет» до тех пор, пока посетитель находится на сайте. Даже когда посетитель меняет страницу сайта на другую, JavaScript дает возможность разработчику переместить на новую страницу уже созданный ранее объект.
Разработчик может самостоятельно управлять созданием страниц и перемещением по нужным деревьям DOM. Но сами по себе объекты и массивы в JavaScript - это не реальные объекты и данные посетителя. В случае с документами посетителем может быть студент, будущий кандидат наук, работник администрации города и т.д., для этих категорий посетителей нужны реальные объекты: документы, а не элементы DOM, родные для JavaScript
Проекты класса PHPOffice/PHPWord - отличное решение и опыт создания взаимодополняющих систем объектов, возможность слежения за рекурсией, учет стековых операций, управление созданием различных объектов, вложенных друг в друга.
Объект JavaScript - это стремление к динамике, но когда это стремление подкреплено реальной практикой хорошего серверного приложения, хорошей реальной задачей с реальной системой объектов - это стремление объективно, работоспособно, надежно и достижимо.
А ЧТО ВЫ ДУМАЕТЕ ОБ ЭТОМ?