היקף של משתנים גלובליים ומקומיים

במאמר הזה נסביר על ההיקף ועל אופן הפעולה שלו ב-JavaScript.

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

ההיקף יכול לעזור לכם:

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

מהו היקף?

ההיקף של המשתנה קובע מאיפה בקוד אפשר להשתמש במשתנה.

JavaScript מגדיר משתנים בעלי היקף גלובלי או מקומי:

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

חלקים מאוחרים יותר במאמר זה דנים בבלוק ובהיקף המילוני:

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

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

כדי להצהיר על משתנה:

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

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

דוגמאות להיקף

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

const greeting = 'hello';
console.log(greeting); // 'hello'

בדוגמה של ההיקף הגלובלי, למשתנה greeting מוקצה ערך hello.

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

function greet() {
  let greeting = 'Hello World!';
  console.log(greeting);
}

בדוגמה הזו מצוין היקף החסימה כי היא מצהירה על המשתנה greeting בתוך בלוק כך שהמשתנה יהיה נגיש רק בתוך הסוגריים המסולסלים:

if (true) {
   const greeting = 'hello';
}

console.log(greeting); // ReferenceError: greeting is not defined

חשוב לשים לב: כשהפונקציה console.log מנסה להפיק את הערך של המשתנה greeting, JavaScript מחזיר הודעת שגיאה ReferenceError במקום הודעת hello הצפויה. למה?

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

הדוגמה הזו מתקנת את השגיאה כי היא מעבירה את השיטה console.log(message) בתוך הסוגריים המסולסלים. הקוד המעודכן מעביר את השיטה console.log(message) לבלוק.

if (true) {
   const greeting = 'hello';
   console.log(greeting);
}

סוגי היקף

היקף גלובלי

ניתן לגשת למשתנים עם היקף גלובלי מכל מקום בתוכנית.

מומלץ להשתמש בקובץ HTML שמייבא שני קובצי JavaScript: file-1.js ו-file-2.js:

<script src="file-1.js"></script>
<script src="file-2.js"></script>

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

אפשר לראות את התוכן של הקבצים file-1.js ו-file-2.js בקטע הקוד הזה. שימו לב לזמינות של המשתנה globalMessage בשני הקבצים.

// file-1.js
function hello() {
    var localMessage = 'Hello!';
}

var globalMessage = 'Hey there!';

// file-2.js
console.log(localMessage); // localMessage is not defined
console.log(globalMessage); // Hey there!

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

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

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

בדוגמה הזו מוצהר על המשתנה total בפונקציה addNumbers(). אפשר לגשת רק למשתנים a, b, ו-total בתוך הפונקציה addNumbers().

function addNumbers(a, b) {
    const total = a + b;
}

addNumbers(3, 4);

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

var variable1 = 'Declared with var';
var variable1 = 'Redeclared with var';
variable1; // Redeclared with var

let variable2 = 'Declared with let. Cannot be redeclared.';
variable2 = 'let cannot be redeclared, but can be updated';
variable2; // let cannot be redeclared, but can be updated

const variable3 = 'Declared with const. Cannot be redeclared or updated';
variable3; // Declared with const. Cannot be redeclared or updated

חסימת ההיקף

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

לדוגמה, בבלוק הזה, ההיקף של המשתנה name והערך שלו "Elizabeth" נמצאים בתוך הסוגריים המסולסלים. משתנים בתוך טווח החסימה לא זמינים מחוץ לבלוק.

{
    const name = "Elizabeth";
}

אפשר להשתמש במשתנים ברמת חסימה במשפטים if, for או while.

יש לשים לב לשתי הלולאות של for בקטע הקוד הזה. לולאת for אחת משתמשת במילת המפתח var כדי להצהיר על משתנה האתחול, שגדל במספרים 0, 1 ו-2. הלולאה השנייה מסוג for משתמשת במילת המפתח let כדי להצהיר על משתנה האתחול.

for (var i = 0; i < 2; i++) {
    // ...
}

console.log(i); // 2

for (let j = 0; j < 2; j++) {
    // ...
}

console.log(j); // The j variable isn't defined.

בדוגמת הקוד הקודמת, ייתכן שהבחנת שהמשתנה i בלולאה הראשונה for הודלף מחוץ ללולאה for ועדיין שומר על הערך 2, כי מילת המפתח var לא משתמשת בהיקף בלוקים. הבעיה תוקנה בלולאת for השנייה שבה המשתנה j שהוצהר עם מילת המפתח let מוקצה לבלוק של הלולאה for ולא קיים אחרי שהלולאה for מסתיימת.

שימוש חוזר בשם משתנה בהיקף אחר

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

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

function listOne() {
    let listItems = 10;
    console.log(listItems); // 10
}

function listTwo() {
   let listItems = 20;
   console.log(listItems); // 20
}

listOne();
listTwo();

למשתנים מסוג listItems בפונקציות listOne() ו-listTwo() מוקצים הערכים הצפויים, כך שאין התנגשות ביניהם.

חסימות והיקף מילוני

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

בדוגמה הזו, הקוד יוצר סגירה עם הסביבה המילונית שנוצרה כשמופעלת הפונקציה outer(), והיא סוגרת מעל המשתנה hello. לכן, המשתנה hello נמצא בשימוש בתוך פונקציית הקריאה החוזרת setTimeout.

function outer() {
    const hello = 'world';

    setTimeout(function () {
        console.log('Within the closure!', hello)
    }, 100);
}

outer();

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

מודולים

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

// hello.js file
function hello() {
  return 'Hello world!';
}

export { hello };

// app.js file
import { hello } from './hello.js';

console.log(hello()); // Hello world!

הדגמה של כלי ההמחשה של ההיקף

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

סיכום

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

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