Menu

let, const ו-var ב-JavaScript: Scope, Hoisting ומתי להשתמש בכל אחד

שלוש הדרכים להצהיר על משתנה ב-JavaScript, ולמה קוד מודרני משתמש ב-const כברירת מחדל, ב-let כשאין ברירה, וב-var כמעט אף פעם.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

שלוש מילות מפתח, תפקיד אחד

ל-JavaScript יש שלוש דרכים להצהיר על משתנה: var, let ו-const. כולן קושרות שם לערך, אבל הן שונות ב_scope_, בכללי ה_הצבה מחדש_, ובהתנהגות שלהן לפני שההצהרה רצה. קוד מודרני משתמש ב-const רוב הזמן, ב-let כשערך צריך להשתנות, וב-var לעתים רחוקות, אם בכלל.

הגרסה הקצרה:

שאר העמוד מסביר למה שלוש השורות האלה מתנהגות כמו שהן מתנהגות.

const: הבחירה ברירת המחדל

const יוצר קישור שאי אפשר להציב מחדש. אחרי שכתבתם const x = 5, אי אפשר לכתוב מאוחר יותר x = 6: המנוע יזרוק TypeError.

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

מקור בלבול נפוץ: const מגן על ה_קישור_, לא על ה_ערך_. אם הערך הוא אובייקט או מערך, עדיין אפשר לשנות את התוכן שלו:

const אומר "השם הזה תמיד מצביע על האובייקט הזה". הוא לא אומר "האובייקט הזה לעולם לא משתנה". אם אתם צריכים שהאובייקט עצמו יוקפא, Object.freeze(user) הוא הכלי, אבל בפועל רוב הקוד פשוט סומך על המוסכמה שלא משנים אובייקטים של const.

let: כשבאמת צריך להציב מחדש

let זהה ל-const בכל דבר חוץ מזה שאפשר להציב אותו מחדש. השתמשו בו למונים, לצוברים, למשתני לולאה ולכל מקום שבו ערך באמת משתנה לאורך זמן.

אם אתם כותבים let ואף פעם לא מציבים מחדש את המשתנה, החליפו אותו ל-const. ה-linter ברוב הפרויקטים ידחוף אתכם לזה.

Block Scope

גם let וגם const הם block-scoped. בלוק הוא כל מה שבין { ל-}: הגוף של if, של for, של פונקציה, או אפילו בלוק { ... } עצמאי. משתנה שהוצהר בתוך בלוק לא קיים מחוצה לו.

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

var לא עושה את זה, וזו הסיבה העיקרית להימנע ממנו.

var: Function Scope והפתעות

var מוגבל ל_פונקציה_ הקרובה, לא לבלוק הקרוב. כלומר, var שהוצהר בתוך if או for דולף החוצה לפונקציה שמסביב:

ה-scope הרופף הזה הוא המקור לרשימה ארוכה של באגים קלאסיים ב-JavaScript, והמפורסם שבהם הוא לולאות שבהן כל האיטרציות חולקות את אותו var i וכל ה-callbacks רואים בסוף את הערך האחרון.

var גם מאפשר להצהיר שוב על אותו שם באותו scope בלי תלונה, וזה מסתיר שגיאות הקלדה:

קוד מודרני משתמש כמעט רק ב-let וב-const. var מופיע בבסיסי קוד ישנים, בתשובות ישנות ב-Stack Overflow ובסקריפטים שצריכים לרוץ בסביבות ישנות מאוד.

Hoisting וה-Temporal Dead Zone

שלוש ההצהרות עוברות hoisting: המנוע יודע עליהן לפני שהוא מריץ את הקוד בבלוק, אבל הן מתנהגות אחרת לפני ששורת ההצהרה רצה.

var עובר hoisting ומאותחל ל-undefined. אפשר לפנות אליו לפני שורת ה-var בלי שגיאה:

let ו-const עוברים hoisting אבל לא מאותחלים. נגיעה בהם לפני ההצהרה זורקת שגיאה. החלון הזה, בין הכניסה ל-scope להרצת ההצהרה, נקרא temporal dead zone (TDZ):

ה-TDZ הוא פיצ'ר, לא באג. הוא הופך "שימוש לפני הצהרה" מ-undefined שקט לשגיאה רועשת, וזה תופס הרבה שגיאות הקלדה וטעויות סדר.

משתנה לולאה const ב-for...of

מקרה קטן אבל נפוץ: לולאות for...of יוצרות קישור חדש בכל איטרציה, ולכן אפשר להשתמש ב-const למשתנה הלולאה, למרות שהוא "משתנה" בין איטרציות.

כל איטרציה מקבלת קישור name משלה: אין משתנה יחיד שמוצב מחדש. לולאה קלאסית for (let i = 0; i < n; i++) עדיין צריכה let, כי i הוא קישור אחד שמקודם.

כלל מעשי

בחרו הצהרות לפי סדר העדיפות הזה:

  • const כברירת מחדל. אם הערך לא יוצב מחדש, תגידו את זה.
  • let כשהקישור באמת צריך להשתנות.
  • var רק כשעובדים בבסיס קוד שדורש אותו.

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

MAX_RETRIES ו-users אף פעם לא משתנים: const. successful גדל: let. user הוא קישור חדש בכל איטרציה: const. בקריאה מלמעלה למטה אפשר להבין אילו ערכים זזים ואילו לא, בלי להריץ את הקוד.

הבא בתור: טיפוסים פרימיטיביים

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

שאלות נפוצות

מה ההבדל בין let, const ו-var ב-JavaScript?

const ו-let הם block-scoped ונוספו ב-ES2015, ואילו var הוא function-scoped וותיק יותר. אי אפשר להציב מחדש קישור של const, ואפשר להציב מחדש קישור של let. var גם עובר hoisting ומאותחל ל-undefined, בעוד ש-let ו-const עוברים hoisting אבל אי אפשר להשתמש בהם עד שההצהרה רצה (ה-temporal dead zone).

האם const הופך ערך לבלתי ניתן לשינוי ב-JavaScript?

לא. const רק מונע הצבה מחדש של הקישור. אם הערך הוא אובייקט או מערך, עדיין אפשר לשנות את התוכן שלו: const user = {}; user.name = 'Ada' עובד בלי בעיה. השתמשו ב-Object.freeze או בספרייה אם אתם צריכים אי-שינוי אמיתי.

האם עדיין כדאי להשתמש ב-var ב-JavaScript מודרנית?

כמעט אף פעם. ל-let ול-const יש כללי scope ברורים יותר, והם תופסים יותר באגים כבר בזמן הפענוח. המקומות היחידים שבהם תפגשו var הם בסיסי קוד ישנים ומדי פעם סקריפט שחייב לרוץ בסביבות בלי תמיכה ב-ES2015.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל