JavaScript ніколи не мав стати тим, чим він є зараз. У 1995 році Брендан Айк, працюючи в Netscape, накидав прототип за десять днів. Десять днів. Цього ледь вистачало, щоб написати пристойну специфікацію, не кажучи вже про розробку мови програмування, призначеної для керування мільярдами пристроїв. Результатом стала мова з особливостями, на яких розробники спотикаються навіть майже три десятиліття потому. Проте це саме поспішне творіння стало найбільш широко впровадженим середовищем виконання в історії програмного забезпечення. Він переміг не тому, що був елегантним, а тому, що з'явився всередині браузера саме в той момент, коли це було потрібно вебу.
Народжений у поспіху
Браузерні війни середини дев'яностих не були дружнім змаганням. Netscape потрібна була легка мова сценаріїв, яка могла б працювати поруч із Java у браузері Navigator. Айку поставили завдання створити щось, що виглядало б достатньо схожим на Java, щоб задовольнити керівництво, але було б достатньо простим, щоб не програмісти могли вставляти його на вебсторінки. Дедлайн був абсурдним. Він створив Mocha, яку невдовзі перейменували на LiveScript, а зрештою — на JavaScript як маркетинговий хід, щоб скористатися популярністю Java.
Цей поспішний початок залишив на ньому постійні шрами. Приведення типів досі плутає новачків, коли оператор «плюс» об'єднує рядки та числа без попередження. typeof null повертає "object" через помилку в оригінальній реалізації, яку ніхто не наважується виправити, щоб не зламати весь веб. Автоматичне вставлення крапки з комою спричиняє приховані помилки. Змінні, оголошені через var, витікають за межі області видимості так, що це здається непередбачуваним. Це не абстрактні недоліки проєктування. Це щоденні труднощі, що безпосередньо походять від двотижневого спринту у травні 1995 року.
Дивне походження
Придивітьсясь до JavaScript, і ви побачите три різні лінії спадковості, зшиті разом. Синтаксис значною мірою запозичений із Java. Фігурні дужки, оператори if та цикли for надають знайомої форми будь-кому, хто прийшов із мов C-подібного стилю. Але під цією поверхнею поведінка зовсім інша.
Справжнє обчислювальне серце мови походить від Scheme, діалекту Lisp. Саме звідси JavaScript отримав функції першого класу, що означає, що функції можна передавати як аргументи, повертати з інших функцій та присвоювати змінним. Це також дало нам замикання (closures), які дозволяють внутрішній функції мати доступ до області видимості зовнішньої функції навіть після того, як ця зовнішня функція завершила виконання. Якщо ви коли-небудь писали callback або додавали слухач подій (event listener), ви використовували ДНК, успадковану від Scheme.
Потім іде модель об'єктів, яка походить від Self. Замість класичного успадкування з жорсткими класами, JavaScript використовує прототипи. Об'єкт може бути пов'язаний безпосередньо з іншим об'єктом і делегувати пошук властивостей вгору по ланцюжку. Ви можете створити об'єкт за допомогою Object.create і будувати ланцюжки, ніколи не визначаючи клас. Сучасний JavaScript додав ключове слово class, але це здебільшого синтаксичний цукор над цією базовою механікою прототипів.
Від декорування сторінок до серйозного інструменту
Протягом перших кількох років JavaScript виконував дрібні завдання. Він перевіряв введення у формах перед відправкою на сервер. Він змінював зображення при наведенні миші. Це була іграшка, а не інструмент. Реалізації в браузерах були несумісними, тому розробники часто писали різні шляхи коду для Netscape та Internet Explorer.
Стандартизація через ECMAScript змінила цю траєкторію. Специфікація дала розробникам браузерів спільну ціль для реалізації, що поступово усунуло найгірші несумісності. Потім з'явився Ajax.
Ajax, скорочення від Asynchronous JavaScript and XML, був не окремою новою технологією, а патерном, що поєднував наявні елементи. Критичним інгредієнтом був об'єкт XMLHttpRequest, який дозволяв браузеру запитувати дані у сервера у фоновому режимі без перезавантаження всієї сторінки. Коли Google запустив Maps у 2005 році та Gmail у 2004 році, користувачі раптом відчули швидкість відгуку, подібну до настільних програм, прямо у вкладці браузера. Вебсторінки перетворилися на додатки. JavaScript більше не був прикрасою. Він став основною стравою.
Швидкість та амбіції
Чиста продуктивність колись була головним жартом JavaScript. Ранні інтерпретатори були повільними. Потім Google випустила двигун V8 у 2008 році разом із Chrome, і жарт перестав бути смішним. V8 запровадив JIT-компіляцію (just-in-time compilation), перетворюючи JavaScript на машинний код під час виконання, а не інтерпретуючи його рядок за рядком. Він запровадив приховані класи (hidden classes) та інлайнове кешування (inline caching), щоб зробити доступ до властивостей швидким навіть для динамічних об'єктів. Інші браузери відповіли власними високошвидкісними двигунами, і мова раптом стала достатньо швидкою для реальних обчислень.
Ця швидкість забезпечила наступний зсув. Раян Даль випустив Node.js у 2009 році, вилучивши V8 із браузера та обгорнувши його в подієво-орієнтовану модель введення-виведення без блокування. Раніше вебсервери створювали новий потік для кожного вхідного запиту, що призводило до їхнього краху при високій конкурентності. Node.js обробляв десятки тисяч одночасних з'єднань на одному потоці, використовуючи цикл подій (event loop) та асинхронні зворотні виклики (callbacks). JavaScript вийшов за межі клієнта на сервер, у інструменти збірки та, зрештою, у все інше.
Мова, що всюдисуща
Тепер JavaScript працює в місцях, про які його творець навіть не міг уявити.
На фронтенді React та Vue визначають те, як будуються сучасні інтерфейси. Компоненти оновлюються у відповідь на зміни стану без виконання браузером ресурсомістких повних перезавантажень сторінок. На бекенді Node.js забезпечує роботу API та сервісів у реальному часі, тоді як новіші середовища виконання, такі як Bun, експериментують із швидшим керуванням пакетами та вбудованою збіркою.
React Native перетворює код JavaScript на нативні представлення платформ, дозволяючи командам випускати мобільні додатки для iOS та Android без необхідності підтримувати дві повністю окремі кодові бази на Swift та Kotlin. Electron обгортає вебтехнології в оболонку Chromium для створення програмного забезпечення для настільних ПК — саме так Slack та Visual Studio Code потрапляють на ваш ноутбук. Мова працює навіть у хмарних функціях та воркерах edge computing, виконуючи логіку за лічені мілісекунди від кінцевого користувача в розподілених мережах.
Парадокс достатку
Всюдисущість має свою ціну. Екосистема величезна, і такий масштаб породжує тривогу. Новий інструмент збірки з'являється ще до того, як ви закінчите налаштовувати попередній. Популярність фреймворків зростає і падає з періодичністю, що нагадує зміну сезонів. Ви можете вирішити майже будь-яку проблему, не залишаючи світу JavaScript, але спочатку маєте обрати серед десятка рішень із дуже специфічним підходом. Дерева залежностей стають глибокими та крихкими. Пакет для додавання пробілів зліва до масивів може зламати тисячі пов'язаних проєктів, коли він зникає з реєстру.
Нічого з цього не є випадковим. JavaScript хаотичний, тому що веб хаотичний. Це органічна багатошарова структура, що складається із зворотної сумісності, поспішних стандартів та конкуруючих інтересів реалізації. Проте саме цей хаос робить мову потужною. Веб є всюди, і оскільки JavaScript за замовчуванням живе в кожному браузері, це найближча річ до універсального середовища виконання, яку ми маємо.
Він давно перестав бути просто скриптовою мовою. Тепер JavaScript — це глобальна платформа для програмного забезпечення, створена за десять днів і що тримається на невидимому контракті: веб не повинен ламати те, що було створено раніше. Вивчаючи його шрами разом із його сильні сторонами, ви вивчаєте історію самого сучасного інтернету.
