משתנים

משתנים הם מבנה נתונים שמקצה שם מייצג לערך. הם יכולים להכיל נתונים מכל סוג.

שם המשתנה נקרא מזהה. צריך לציין מזהה חוקי אחרי כללים אלה:

  • מזהים יכולים לכלול אותיות Unicode, סימני דולר ($), קו תחתון בתווים (_), ספרות (0-9) ואפילו תווי Unicode מסוימים.
  • מזהים לא יכולים להכיל רווחים לבנים, כי המנתח משתמש ברווח לבן כדי של רכיבי קלט נפרדים. לדוגמה, אם מנסים לקרוא למשתנה my Variable במקום myVariable, המנתח רואה שני מזהים: my ו-Variable, וזורקת שגיאת תחביר ("אסימון לא צפוי: ".
  • המזהים חייבים להתחיל באות, בקו תחתון (_) או בסימן דולר ($). הם לא יכולים להתחיל בספרות, כדי למנוע בלבול בין מספרים מזהים:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    אם JavaScript מאפשר שימוש במספרים בתחילת מזהה, הדבר יאפשר המזהים שמורכבים ממספרים בלבד, וגורמים להתנגשות בין מספרים שמשמשים מספרים ומספרים המשמשים כמזהים:

    let 10 = 20
    
    10 + 5
    > ?
    
  • "מילים שמורות" אם יש להם משמעות תחבירית, אי אפשר להשתמש בהם כמזהים.

  • מזהים לא יכולים להכיל תווים מיוחדים (! . , / \ + - * =).

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

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

let camelCasedIdentifier = true;

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

class MyClass {

}

המזהים צריכים לתאר בקצרה את אופי הנתונים שהם מכילים (ל לדוגמה, currentMonthDays הוא השם טוב יותר מאשר theNumberOfDaysInTheCurrentMonth) וקריאה בבירור במבט מהיר (originalValue טוב יותר מ-val). myVariable מזהים שנמצאים בשימוש במודול הזה פועלים בהקשר של אבל בדוגמאות בודדות, זה לא יהיה שימושי מאוד בקוד הייצור, כי לא מספקים שום מידע על הנתונים שהם מכילים.

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

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

הצהרה לגבי משתנים

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

let myVariable;

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

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

משתנה מוצהר מאתחל על ידי הקצאת ערך למשתנה. צריך להשתמש ב סימן שוויון יחיד (=) כדי להקצות או להקצות מחדש ערך למשתנה. אפשר לבצע כחלק מאותה הצהרה שמצהירה על כך:

let myVariable = 5;

myVariable + myVariable
> 10

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

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

משתנה עם ערך undefined שונה ממשתנה לא מוגדר המזהה עדיין לא הוצהר. הפניה למשתנה שלא מוצהר וגורם לשגיאה.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

שיוך של מזהה לערך נקרא בדרך כלל 'קישור'. התחביר שמופיע אחרי מילות המפתח let, var או const נקרא "binding list", והוא מאפשר כמה הצהרות עם משתנים מופרדים בפסיקים (שמסתיים בתו נקודה-פסיק הצפוי). הפעולה הזו יוצרת את קטעי הקוד הבאים זהות מבחינה פונקציונלית:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

להקצאה מחדש של ערך משתנה לא נעשה שימוש ב-let (או ב-var), מפני ש-JavaScript כבר יודע שהמשתנה קיים:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

אפשר להקצות מחדש למשתנים ערכים חדשים על סמך הערכים הקיימים שלהם:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

אם מנסים להצהיר מחדש על משתנה באמצעות let בסביבת הייצור, תקבלו שגיאת תחביר:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

דפדפנים כלים למפתחים שמעניקות לך יותר הרשאות לגבי הצהרה מחדש של let (ו-class), כך שייתכן שלא רואים את אותה שגיאה ב-Developer Console.

כדי לשמור על תאימות של דפדפנים מדור קודם, var מאפשר הצהרה מחדש שאין בה צורך ללא שגיאה באף הקשר:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

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

const myConstant = true;

myConstant
> true

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

const myConstant;
Uncaught SyntaxError: missing = in const declaration

לנסות לשנות את הערך של משתנה שהוצהר באמצעות const, באופן שבו אפשר שינוי הערך של משתנה מוצהר עם let (או var) גורם לסוג שגיאה:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

אבל כשקבוע משויך לאובייקט, המאפיינים של את האובייקט שניתן לשנות.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

קבוע שמכיל אובייקט הוא בלתי ניתן לשינוי הפניה לערך נתונים שניתן לשינוי. לא ניתן לשנות את הקבוע עצמו, אבל המאפיינים של ההפניה אפשר לשנות, להוסיף או להסיר אובייקט:

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

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

היקף המשתנים

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

בהתאם למילת המפתח שבה משתמשים כדי להצהיר על משתנה ולהקשר איך מגדירים אותו, אפשר להגביל את ההיקף של המשתנים כדי לחסום הצהרות (היקף חסימה), פונקציות בודדות (היקף הפונקציה), או כל האפליקציה של JavaScript (היקף גלובלי).

חסימת היקף

כל משתנה שמצהירים עליו באמצעות let או const תוקצה להיקף הקרוב ביותר שלו שמכיל הצהרת חסימה, כלומר ניתן לגשת למשתנה רק בתוך אותו בלוק. מתבצע ניסיון גישה למשתנה ברמת בלוק מחוץ לבלוק שמכיל אותו גורם ומנסה לגשת למשתנה שאינו קיים:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

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

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

משתנה שהוצהר לא יכול להרחיב את בלוק ההורה שלו, אבל הוא כן לכל בלוק הצאצאים:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

אפשר לשנות את הערך של משתנה מוצהר מתוך בלוק צאצא:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

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

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

היקף הפונקציה

משתנים שהוצהרו באמצעות var בהיקף של הפונקציה שמכילה את המשתנים הקרובים ביותר (או בלוק אתחול סטטי בתוך מחלקה).

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

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

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

היקף גלובלי

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

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

כל משתנה שהוצהר באמצעות var מחוץ לפונקציית הורה, או באמצעות let או const מחוץ לבלוק הורה, הוא גלובלי:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

הקצאת ערך למשתנה בלי להצהיר עליו במפורש (כלומר אף פעם לא משתמשים ב-var, ב-let או ב-const כדי ליצור אותו) מעלה משתנה היקף גלובלי, גם כשהוא מאותחל בתוך פונקציה או בלוק. משתנה שנוצר באמצעות הדפוס הזה נקרא לפעמים "משתמע גלובלי".

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

הרמה משתנה

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

hoistedVariable
> undefined

var hoistedVariable;

כי רק הצהרת המשתנה מתארחת, לא האתחול, משתנים שלא הוצהרו במפורש באמצעות var, let או const שלא יועלו:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

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

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

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

let ו-const מטפלים בהתנהגות הזו על ידי הרצת שגיאה כאשר מתבצעת גישה למשתנה לפני שהוא נוצר:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

השגיאה הזו שונה מהשגיאה "hoistedVariable is לא מוגדר" שגיאה כשתנסו לגשת למשתנה לא מוצהר. כי JavaScript מעלה את המשתנה, הוא מודע לכך שהמשתנה ייווצר את ההיקף הנתון. עם זאת, במקום להפוך את המשתנה לזמין לפני עם הערך undefined, המתרגם זורק שגיאה. משתנים שהוצהרו עם let או const (או class) נחשבים כקיימים 'אזור מתים זמני' ("TDZ") מתחילת החסימה שלו עד של הנקודה בקוד שבה הוצהר על המשתנה.

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

בדיקת ההבנה

עם אילו סוגי תווים אפשר להתחיל מזהה?

ספרה
קו תחתון
אות

מהי השיטה המועדפת להצהרה על משתנה שהערך שלו ניתן לשנות בכל שלב?

const
ו
מאפשר