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

במאמר הזה נסביר על ההיקף ואיך הוא פועל ב-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 רק בתוך הסוגריים המסולסלים, שמציין את היקף הבלוק.

דוגמה זו מתקנת את השגיאה כי היא מעבירה את ה-method console.log(message) בתוך הסוגריים המסולסלים. הקוד המעודכן מעביר את ה-method 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 הוא אחד מהמושגים המתקדמים יותר בפיתוח אתרים, ולכן טוב שקראת את התוכן והקדשת זמן כדי להבין את הנושא.

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