JavaScript לא נועדה להפוך למה שהיא היום. ב-1995, ברנדן אייך התיישב ב-Netscape ופיתח אב-טיפוס תוך עשרה ימים. עשרה ימים. זה בקושי מספיק זמן לכתיבת מפרט ראוי, שלא לדבר על עיצוב שפת תכנות שנועדה להניע מיליארדי מכשירים. התוצאה הייתה שפה עם מוזרויות שמפתחים עדיין נתקלים בהן כמעט שלושה עשורים מאוחר יותר. ובכל זאת, אותה יצירה ממהרת הפכה לסביבת ההרצה (runtime) הנפוצה ביותר בהיסטוריה של התוכנה. היא ניצחה לא בגלל שהייתה אלגנטית, אלא בגלל שהיא הופצה בתוך הדפדפן בדיוק ברגע שהאינטרנט היה זקוק לה.

נולדה בחיפזון

מלחמות הדפדפנים באמצע שנות התשעים לא היו תחרות ידידותית. Netscape הייתה זקוקה לשפת סקריפטים קלה שתוכל לרוץ לצד Java בדפדפן Navigator שלה. אייך קיבל את המשימה לבנות משהו שנראה מספיק כמו Java כדי לרצות את המנהלים, אך פשוט מספיק כדי שמפתחים לא מקצועיים יוכלו להדביק אותו לדפי אינטרנט. הדדליין היה אבסורדי. הוא הפיק את Mocha, ששונה במהרה ל-LiveScript, ולבסוף ל-JavaScript כצעד שיווקי כדי לרכוב על הפופולריות של Java.

הלידה המהירה הזו הותירה צלקות קבועות. המרה אוטומטית של טיפוסים (Type coercion) עדיין מבלבלת מתחילים כאשר אופרטור הפלוס מחבר מחרוזות ומספרים ללא אזהרה. typeof null מחזיר "object" בגלל באג במימוש המקורי שאף אחד לא מעז לתקן מחשש לשבור את האינטרנט. הכנסת נקודה-פסיק (semicolon) אוטומטית גורמת לכשלים שקטים. משתנים המוגדרים עם var דולפים בטווח ההקשר (scope) בדרכים שמרגישות בלתי צפויות. אלו אינן פגמים עיצוביים מופשטים. אלו תסכולים יומיומיים שניתן להצביע ישירות על המקור שלהם: ספרינט של שבועיים במאי 1995.

אילן יוחסין מוזר

הביטו מקרוב ב-JavaScript ותראו שלושה שושלות נפרדות השזורות יחד. התחביר שואב השראה רבה מ-Java. סוגריים מסולסלים, משפטי if ולולאות for מספקים צורה מוכרת לכל מי שמגיע משפות בסגנון C. אך מתחת לפני השטח, ההתנהגות שונה לחלוטין.

הלב החישובי האמיתי של השפה מגיע מ-Scheme, דיאלקט של Lisp. כאן קיבלה JavaScript פונקציות מסדר ראשון (first-class functions), מה שאומר שניתן להעביר פונקציות כארגומנטים, להחזיר אותן מפונקציות אחרות ולהקצות אותן למשתנים. זה גם העניק לנו closures, המאפשרים לפונקציה פנימית לגשת לטווח ההקשר של פונקציה חיצונית גם לאחר שהפונקציה החיצונית סיימה את פעולתה. אם אי פעם כתבת callback או צמדת event listener, השתמשת ב-DNA שירשת מ-Scheme.

ואז יש את מודל האובייקטים, שמגיע מ-Self. במקום ירושה קלאסית עם מחלקות (classes) נוקשות, JavaScript משתמשת ב-prototypes. אובייקט יכול להתחבר ישירות לאובייקט אחר ולהאציל לו חיפושי מאפיינים (property lookups) כלפי מעלה. ניתן ליצור אובייקט באמצעות Object.create ולבנות שרשראות מבלי להגדיר מחלקה מעולם. JavaScript המודרנית הוסיפה את מילת המפתח class, אך היא בעיקרה "סוכר תחבירי" (syntactic sugar) מעל מנגנון ה-prototype הבסיסי הזה.

מקישוט דפים לכלי רציני

בשנותיה הראשונות, JavaScript ביצעה משימות קטנות. היא אימתה קלטים בטפסים לפני שהם נשלחו לשרת. היא החליפה תמונות במעבר עכבר (mouse hover). היא הייתה צעצוע, לא כלי. המימושים בדפדפנים היו לא עקביים, ולכן מפתחים נאלצו לעיתים קרובות לכתוב נתיבי קוד שונים עבור Netscape ו-Internet Explorer.

הסטנדרטיזציה באמצעות ECMAScript שינתה את המסלול הזה. המפרט נתן ליצרני דפדפנים מטרה משותפת למימוש, מה שבהדרגה החליק את חוסר התאימות הגרוע ביותר. ואז הגיע ה-Ajax.

Ajax, קיצור של Asynchronous JavaScript and XML, לא היה טכנולוגיה חדשה אחת אלא תבנית ששילבה חלקים קיימים. המרכיב הקריטי היה אובייקט ה-XMLHttpRequest, שאפשר לדפדפן לבקש נתונים מהשרת ברקע מבלי לטעון מחדש את כל הדף. כשגוגל השיקה את Maps ב-2005 ואת Gmail ב-2004, המשתמשים חוו לפתע תגובתיות דמויית שולחן עבודה בתוך לשונית דפדפן. דפי אינטרנט הפכו לאפליקציות. JavaScript כבר לא הייתה רק קישוט. היא הפכה למנה העיקרית.

מהירות ושאיפות

הביצועים הגולמיים היו בעבר הבדיחה הגדולה ביותר של JavaScript. ה-interpreters המוקדמים היו איטיים. ואז גוגל שחררה את מנוע V8 בשנת 2008 לצד Chrome, והבדיחה הפסיקה להיות מצחיקה. V8 הציג קומפילציה בזמן ריצה (just-in-time compilation), המתרגמת את JavaScript לקוד מכונה בזמן ריצה במקום לפרש אותה שורה אחר שורה. הוא הציג hidden classes ו-inline caching כדי להפוך את הגישה למאפיינים למהירה גם באובייקטים דינמיים. דפדפנים אחרים הגיבו עם מנועים מהירים משלהם, והשפה הפכה לפתע למהירה מספיק לחישובים אמיתיים.

המהירות הזו אפשרה את השינוי הבא. ריין דאל שחרר את Node.js בשנת 2009, כשהוא מוציא את V8 מהדפדפן ועוטף אותו במודל קלט-פלט (I/O) מונחה אירועים ובלתי חוסם (non-blocking). שרתי אינטרנט נהגו ליצור תהליכון (thread) חדש עבור כל בקשה נכנסת, מה שהוביל לקריסה תחת עומס של ריבוי משימות (concurrency) גבוה. Node.js טיפל בעשרות אלפים של חיבורים בו-זמניים על תהליכון בודד באמצעות לולאת אירועים (event loop) וקריאות חוזרות אסינכרוניות (asynchronous callbacks). JavaScript "נשפכה" מהלקוח אל השרת, לכלי בנייה (build tools), ובסופו של דבר לכל דבר אחר.

השפה שנמצאת בכל מקום

כיום JavaScript רצה במקומות שיוצרה מעולם לא דמיין.

בצד הלקוח (frontend), React ו-Vue מעצבות את האופן שבו ממשקים מודרניים נבנים. רכיבים מתעדכנים בתגובה לשינויי מצב (state) מבלי שהדפדפן יבצע טעינה מחדש יקרה של כל הדף. בצד השרת (backend), Node.js מניע APIs ושירותי זמן אמת, בעוד סביבות הרצה (runtimes) חדשות יותר כמו Bun מתנסות בניהול חבילות מהיר יותר וב-bundling מובנה.

React Native מתרגמת קוד JavaScript לתצוגות פלטפורמה טבעיות (native), מה שמאפשר לצוותים להוציא לאור אפליקציות מובייל עבור iOS ו-Android מבלי לתחזק שני בסיסי קוד נפרדים לחלוטין ב-Swift וב-Kotlin. Electron עוטפת טכנולוגיות אינטרנט בתוך מעטפת Chromium כדי לבנות תוכנות שולחן עבודה, וזו הדרך שבה גם Slack וגם Visual Studio Code מגיעים למחשב הנייד שלך. השפה אפילו נמצאת בתוך פונקציות ענן (cloud functions) ועובדי מחשוב קצה (edge computing workers), ומבצעת לוגיקה במרחק של מילישניות בלבד מהמשתמש הקצה ברשתות מבוזרות.

פרדוקס השפע

לנוכחות בכל מקום יש מחיר. האקוסיסטם הוא עצום, והגודל הזה מוליד חרדה. כלי בנייה חדש מופיע עוד לפני שסיימת להגדיר את האחרון. פריימוורקים עולים ויורדים בפופולריות בלוחות זמנים שמרגישים עונתיים. ניתן לפתור כמעט כל בעיה מבלי לעזוב את עולם ה-JavaScript, אך תחילה עליכם לבחור בין תריסר פתרונות בעלי גישה מאוד מוגדרת (highly opinionated). עצי התלות (dependency trees) הופכים לעמוקים ושבירים. חבילה פשוטה לריפוד שמאלי של מערכים (left-padding arrays) יכולה לשבור אלפי פרויקטים המסתמכים עליה ברגע שהיא נעלמת מהרישום (registry).

שום דבר מזה אינו מקרי. JavaScript מבולגנת כי האינטרנט מבולגן. היא עוגת שכבות אורגנית של תאימות לאחור (backward compatibility), תקנים ממהרים ואינטרסים מתחרים של מימושים שונים. ובכל זאת, אותו בלאגן הוא הסיבה לכך שהשפה כה עוצמתית. האינטרנט נמצא בכל מקום, ומכיוון ש-JavaScript חיה בתוך כל דפדפן כברירת מחדל, היא הדבר הקרוב ביותר שיש לנו לסביבת הרצה (runtime) אוניברסלית.

היא חדלה להיות סתם שפת סקריפטים מזמן. JavaScript היא כיום פלטפורמה גלובלית לתוכנה, שנבנתה בעשרה ימים, ומחוברת על ידי החוזה הבלתי נראה שהאינטרנט לא יפר את מה שהיה לפניו. למדו את הצלקות שלה לצד החוזקות שלה, ואתם לומדים את ההיסטוריה של האינטרנט המודרני עצמו.