Monkey patching

טכניקה פשוטה (ומסוכנת) להוספת תכונות לאובייקטים קיימים בג'אווהסקריפט שכדאי להכיר

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

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

const myArray = ['avi', 'itzik', 'yaki'];

console.log(myArray.endsWith('yaki')); // true

console.log(myArray.endsWith('sarah')); // false

אם תריצו את הקוד הזה, תקבלו שגיאה מסוג:
Uncaught TypeError: myArray.endsWith is not a function

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

const Utils = {
  endsWith: (arr, arg) => arr[arr.length - 1] === arg ? true : false,
}

const myArray = ['avi', 'itzik', 'yaki'];

console.log(Utils.endsWith(myArray, 'yaki')); // true;

אבל זה עלול להיות מעיק ובעייתי. צריך לזכור שיש את ה-Utils וכל מי שכתב קוד מורכב יודע שספריות העזר האלו נוטות להתנפח. זה הדבר הכדאי לעשות בסופו של דבר, אבל יש דרך נוספת שנקראת Monkey Patching – לשנות את הקוד בזמן הריצה או יותר נכון, בג'אווהסקריפט, לשנות את הפרוטוטייפ של האובייקט בזמן אמת. בג'אווהסקריפט יש לנו את prototype, שמהווה את הבסיס של השפה. לכל אובייקט ואובייקט אפשר לגשת ולשנות את המתודות שלו באמצעות prototype. אני יכול להעניק לסוג המידע הפרימיטיבי Array את המתודה endsWith כך שתהיה זמינה במערך.

Array.prototype.endsWith = function(arg) {
  return this[this.length - 1] === arg ? true : false;
}

const myArray = ['avi', 'itzik', 'yaki'];

console.log(myArray.endsWith('yaki')); // true

console.log(myArray.endsWith('sarah')); // false

See the Pen monkey patching JavaScript array by Ran Bar-Zik (@barzik-the-vuer) on CodePen.

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

אני יכול לשנות גם תכונה קיימת כמובן. גם עם פרוטוטייפ אבל גם לשנות דברים בסקופ הגלובלי (פעם היינו משתמשים ב-window, היום ב-globalThis) למשל, אם אני רוצה שכל console.log יודפס דווקא כ-console.error, אני יכול לעשות משהו כזה:

globalThis.console.log = (arg) => globalThis.console.error(arg);

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

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

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

אם אתם בוחרים ב-monkey patching למרות האזהרות, כדאי מאוד להקיף את השימוש במתודה הנוספת בבדיקה שהיא קיימת. באופן אישי? למעט דיבאגינג או שינוי ה-console.log, אני נמנע מכך. אבל חשוב להכיר את המונח.

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

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

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

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

המנעו מהעלאת source control לשרת פומבי

לא תאמינו כמה אתרים מעלים את ה-source control שלהם לשרת. ככה תמצאו אותם וגם הסבר למה זה רעיון רע.

ESP32 מאפס לילדים

מדריך ל-ESP32 לילדים ולהורים מאפס

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

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