ECMAScript 6 – סקופ נפרד לכל בלוק עם let

הגדרת משתנה שיש לו סקופ משלו בכל קטע קוד

במאמר הקודם למדנו על קבוע, במאמר הזה אנחנו נדבר על אחד מסימני ההיכר החזקים של ECMAScript 6 – הגדרת משתנה עם let.

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


"use strict";
var x = 5;

function moshe () {
  var x = 123;
  console.log(x); //Will be 123
}

console.log(x); //Will be 5
moshe();
console.log(x); //Will be 5

אם נפעיל את הקוד הבא (ואתם יכולים להעתיק ולהדביק אותו בקונסולה של כלי המפתחים), יהיה אפשר לראות שהקונסולה תראה לנו

5
123
5

למה? כי לפונקציה moshe יש סקופ משלה שבה המשתנה X נפרד לחלוטין ממשתנה X הגלובלי. בשניה שאנחנו מגדירים משתנה עם var בתוך פונקציה, אנחנו יוצרים משתנה פרטי בסקופ שאיתו אפשר לעבוד אבל הוא לא רלוונטי ל'עולם החיצוני' שמחוץ לפונקציה.

מה הבעיה? שהיה אפשר להגדיר scope רק לפונקציות ולא לבלוקים אחרים כמו למשל משפטי תנאי.

בואו ונדגים עם הקוד הבא:


"use strict";

 var x = 5;

if (true) {
  var x = 123;
  console.log(x); //Will be 123
}

console.log(x); //Will be 123

מה קורה פה? אנחנו מגדירים var בתוך ה-if, ל-if היה אמור להיות סקופ משלו. אבל אין כזה דבר ב-ECMAScript 5. לא יכולנו להגדיר scope משלנו מתי שבא לנו אלא רק בתוך פונקציה.

בדיוק בשביל זה יש לנו את ECMAScript 6 ואת let שמאפשר לנו להגדיר סקופ איפה שבא לנו. אפילו במשפט תנאי:


"use strict";

 var x = 5;

if (true) {
  let x = 123;
  console.log(x); //Will be 123
}

console.log(x); //Will be 5

אפשר להריץ את זה בקונסולה או לפתוח את הקונסולה שלכם ולראות את זה רץ ב-codepen:

See the Pen ECMAScript 6 – Let by Ran Bar-Zik (@barzik) on CodePen.

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


var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener('click', function() {
    console.log('You clicked button #' + i);
  });
}

הי הי הי! לא להתעלף פה! הקוד הזה די פשוט. מה שהוא עושה זה להשתמש בשאילתת JS פשוטה על מנת להכניס את כל אלמנטי ה-DOM שהם כפתורים אל מערך buttons. באמצעות לולאות for פשוטה אני מצמיד אירוע לחיצה לכל כפתור שמדפיס לקונסולה את המספר הסידורי של כל כפתור.

מה הבעיה? שועלי JS ותיקים כבר ידעו ישר. אבל למי שלא, העזרו ב-codepen הבא:

See the Pen ECMAScript 5 Scope failure by Ran Bar-Zik (@barzik) on CodePen.

לחיצה על הכפתור תראה לנו שבקונסולה אנחנו רואים כל פעם
"You clicked button #3"
בהנחה שיש שלושה כפתורים. אבל רגע, למה? למה אני לא רואה כל פעם את המספר של הכפתור שנלחץ? בדיוק בגלל בעית ה-scope! מחוץ ל-addEvent ה-i קבוע, אבל בתוך ההצמדה של האירוע ההתיחסות ל-i היא גלובלית. זה קשה להבנה באופן אינטואיטיבי, אבל כל מתכנת JS מספיק מנוסה נתקל בבעיה הזו.
יש כמה דרכים לפתור את זה, כולן דוחות למדי, למשל דרך אחת היא:


var buttons = document.getElementsByTagName('button');

for (var i = 0; i < buttons.length; i++) {
  bindEvent(i);
}

function bindEvent(k) {
  var button = buttons[k]
  button.addEventListener('click', function() {
    console.log(k);
  });
}

See the Pen ECMAScript 5 Scope failure – solution by Ran Bar-Zik (@barzik) on CodePen.

מה שקורה פה הוא שאנחנו בעצם מכריחים את JS ליצור סקופ חדש באמצעות הגדרת פונקציה. ואז ה-i שמשתמשים בו הוא מקומי ולא גלובלי. די פשוט (אם אתם יודעים את הפתרון) אבל מסובך למדי אם לא מבינים עד הסוף את עניין ה-scope או שאתם באמצע ראיון עבודה מלחיץ או שיש דד-ליין.

ברגע שיש הבנה בנוגע לסקופ עם ECMAScript 6 הפתרון הוא פשוט, באמצעות let נאכוף את הסקןפ החדש בקלות רבה, בלי להשתמש בפונקציות מלאכותיות בכוח על מנת ליצור סקופ חדש:


var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
  let j = i;
  buttons[j].addEventListener('click', function() {
    console.log('You clicked button #' + j);
  });
}

אתם מוזמנים לבחון את הפתרון כאן:

See the Pen ECMAScript 5 Scope failure solution by ES6 by Ran Bar-Zik (@barzik) on CodePen.

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

פוסטים נוספים שכדאי לקרוא

עבודה בהיי טק

איך מראיינים סניורים?

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

פתרונות ומאמרים על פיתוח אינטרנט

עבודה עם GPT למתכנתים

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

פתרונות ומאמרים על פיתוח אינטרנט

SSG עם next

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

DALL·E 2023-10-21 22.28.58 - Photo of a computer server room with red warning lights flashing, indicating a potential cyber threat. Multiple screens display graphs showing a sudde
יסודות בתכנות

מבוא לאבטחת מידע: IDOR

הסבר על התקפה אהובה ומוצלחת שבאמצעותה שואבים מידע מאתרים

פתרונות ומאמרים על פיתוח אינטרנט

רינדור של קליינט סייד עם SSR

הסבר קצר על SSR מול רינדור קלאסי ולא. לא תמיד זה טוב להשתמש בו. אין כדור כסף שיכול לפתור הכל.

גלילה לראש העמוד