Перехід від класичного програмування до об’єктно-орієнтованого давно проголошений, але досі не завершено, а всі сучасні мови програмування вже давно мають власні об’єктно-орієнтовані концепції і синтаксис.
Про відмінності, стеку та рекурсії
Відмінності між реалізаціями об’єктно-орієнтованої доктрини мовами програмування, різниця в їх філософії і розумінні нової логіки їх авторами та розробниками велика.
Рівень організації стекової даних і рівень рекурсії сучасних алгоритмів в області інтернет-програмування низькі і не часто зустрічаються. Локальне програмування застосовує стек і рекурсію тільки при явної необхідності або при прямому вказуванні завдання на розробку.
Ці обставини свідчать про те, що динаміка змінної і динаміка набору значень (масив) в процесі виконання алгоритму знаходяться на початковому рівні розвитку уявлень про даних та алгоритмах.
Можливо, це не так, а світ інтернет-програмування стрімко розвивається.
Якщо змінна (у тому числі в статусі масиву або об’єкта) – це стек, то з’являється історія значень і можливість переміщатися по ній у пошуках потрібної інформації (значення) чи оптимального рішення (множини значень).
Якщо функція (алгоритм) являє собою послідовність дій без рекурсії (без можливості викликати саму себе) – це глухий кут, який не може розвиватися без сторонньої допомоги (без участі програміста).
Навіть якщо мета функції не розвиток своєї функціональності, але рекурсивна функція, вона може претендувати на статус повнофункціонального рішення, а це важливо, це рівень програмування та оцінка кваліфікації програміста.
Мінлива, її значення та місце в алгоритмі
Відстань між змінною і масивом мізерно на лінії розвитку програмування.
Змінні вмить стали звичними і відразу привели до створення різних структур даних. З’явилися масиви, структури, записи та інші конструкції перших мов програмування.
Коли панував Фортран і Бэйсик, про об’єкти ще навіть не мріяли, а класичний синтаксис оператора – це була окрема рядок коду.Тільки у виняткових випадках можна було писати в одній сходинці пару операторів.
Масиви з’явилися швидко, але досі немає розуміння змінної як місця в алгоритмі, тобто моменту зміни її значення і поняття історії цих моментів.
Поняття «відкату» – прерогатива прикладних програм. Операційні системи і мови програмування ніколи не брали до уваги доцільність і важливість історії дій (подій) і право програміста/користувача на їх скасування.
Досі поняття історії дій і можливості руху по ній (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 – це прагнення до динаміки, але коли це прагнення підкріплена реальною практикою хорошого серверного додатка, хорошою реальним завданням з реальною системою об’єктів – це прагнення об’єктивно, працездатне, надійно й досяжне.