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, אני נמנע מכך. אבל חשוב להכיר את המונח.

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

אהבתם? לא אהבתם? דרגו!



אל תשארו מאחור! יש עוד מה ללמוד!

5 comments on “Monkey patching
  1. משתמש אנונימי (לא מזוהה) הגיב:

    תודה. איך בודקים שהמתודה קיימת?

  2. יותם הגיב:

    למה בדוגמת הקוד יש גם === וגם לאחר מכן ?true:flase? הערך שמחזיר === הוא בעצמו בוליאני

  3. חיים ארוכים הגיב:

    חסר הסבר למה לעזאזל זה נקרא monkey patching ולא cute cat patching.

כתיבת תגובה

האימייל לא יוצג באתר.

רישום