אינטרנט ישראל
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
  • ראשי
  • אודות רן בר-זיק ואינטרנט ישראל
  • ערוץ טלגרם
  • מסטודון
  • התחברו אלי בטוויטר
  • התחברו אלי בלינקדאין
  • ספר ג'אווהסקריפט
ראשי » פיתוח אינטרנט » פתרונות ומאמרים על פיתוח אינטרנט » על שרשרת הפרוטוטייפ ב-JavaScript, הסכנות והיתרונות שלה

על שרשרת הפרוטוטייפ ב-JavaScript, הסכנות והיתרונות שלה

רן בר-זיק ספטמבר 18, 2016 7:07 am תגובה אחת

הסבר פשוט על אחד מהנושאים האלמנטריים והחשובים ביותר בג'אווהסקריפט

כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.

המאמר הזה מדבר על JavaScript ועל העצמים שלה. מי שמחפש מאמר למתחילים על תכנות מונחה עצמים בג'אווהסקריפט שייכנס למאמר שלי למתחילים שכתבתי לפני כמה שנים. המאמר הזה מיועד למתכנתים שמכירים תכנות מונחה עצמים ורוצים לדעת יותר על prototype chain וירושה בג'אווהסקריפט.

למרות שב-ES6 יש לנו קלאסים, מדובר ב'סוכר סינטקטי'. בניגוד לשפות אחרות, ג'אווהסקריפט היא לא מבוססת מחלקות אלא על פרוטוטייפ (בלעז prototype). ההבדל הוא דק אך משמעותי ויכול, ככל שאנחנו מתבססים יותר ויותר על JavaScript להיות משמעותי עבור הקוד שאתם כותבים. במאמר הזה אני אדבר על שרשרת פרוטוטייפ ב-JavaScript. אתם יותר ממוזמנים להעתיק את הקוד לקונסולה שלכם ולבדוק בעצמכם.

אז בואו ונתחיל עם אובייקט פשוט:


var o = {a: 1, b: 1}

אם נכניס את זה לקונסולה, אנו נראה את האובייקט, אם נחפור קצת יותר פנימה נראה משהו כזה:

Object {a: 1, b: 2}a: 1b: 2__proto__: Object

מה זה __proto__? מדובר ב'אב הטיפוס' של מה שיצרנו. לכל דבר בג'אווהסקריפט יש אב טיפוס משלו. למשל, אם ניצור פונקציה נראה שה-__proto__ שלה הוא פונקציה, אבל ה-__proto__ של הפונקציה הוא object (בג'אווהסקריפט כמעט הכל מגיע ל-object). מה ה-__proto__ של object? פה מדובר ב-null. ל-nul אין פרוטוטייפ והוא הסוף של שרשרת הפרוטוטייפ.

o Object {a: 1, b: 2} o.__proto__ Object {} o.__proto__.__proto__ null

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

בואו ונראה איך אנחנו יורשים מאובייקט מסוים. החל מ-ES5, מקובל לרשת אובייקטים באמצעות Object.create. בואו נראה דוגמה:


var o = {
  a: 2,
  m: function(b){
    return this.a + 1;
  }
};

var p = Object.create(o);



אובייקט p הוא אובייקט שיורש מ-o. אני יכול להסתכל על הירושה באופן הבא עם הקונסולה:

p Object {}__proto__: Objecta: 2m: (b)__proto__: Object

מה יקרה אם אני אעשה משהו כזה?


p.m(); //returns 3

אני אקבל 3, כיוון שזה מה בדיוק מה שיש באובייקט a, אובייקט p הוא העתק מושלם של אובייקט a. מה לפי דעתכם יקרה אם אני אעשה משהו כזה?


p.m(); //3
o.a = 10; 
p.m(); //Now it is 11!

למה זה קורה? כי Object.create יוצר העתק מושלם, והתכונה a קיימת רק באובייקט המקורי. שינוי שלו זה שינוי בכל הפרוטוטייפ ואפשר לראות את זה אם מסתכלים בקונסולה:

למשתנה p יש רק __proto__

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

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

אחרי שעשינו override ל-a, הוא מתנתק מהפרוטוטייפ ויש לו זכות קיום משלו.

אחרי שעשינו override ל-a, הוא מתנתק מהפרוטוטייפ ויש לו זכות קיום משלו. זה הדבר הכי חשוב בכל המאמר הזה – שברגע שאני עושה override, הפרוטוטייפ כבר לא חשוב ולא מעניין. לפחות בנוגע לאובייקט שבו אני עובד כרגע.

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

אפשר להשתמש ב-object create לכל דבר. כל דבר הוא אובייקט.
אפשר להשתמש ב-object create לכל דבר. כל דבר הוא אובייקט.

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

על מנת לוודא שלאובייקט יש את התכונה שאני מחפש והערך לא מגיע מה-__proto__ אני יכול להשתמש ב hasOwnProperty


p.hasOwnProperty('a') //true
p.hasOwnProperty('m') //false, it is only in the __proto__

לצורך העניין פונקציה גם היא property.

נשאלת השאלה מה קורה אם אתה רוצה לרשת מאובייקט אבל ללא שרשרת פרוטוטייפ בכלל. כלומר רק לרשת את התכונות הקיימות? בדיוק בשביל זה יש ספריות עזר כמו lodash שיעזרו לביצוע cloning. ניתן גם להשתמש ב-constructor, שעובד עם new.

עבודה עם new היא סוג של מעקף או 'סוכר סינטקטי', כי בעצם אנחנו מנסים להמיר את ה-Prototypical Inheritance ב-פסאודו קלאס. כלומר משהו שנראה כמו קלאס, מתנהג כמו קלאס אבל מאחורי הקלעים הוא מתנהג בדיוק כמו אובייקט. איך עושים את זה? פשוט למדי:


function o() {
this.a = 1;
this.b = 2
}

o.prototype.myMethod = function() {
return this.a + this.b;
}

myObj = new o();

זה כבר משהו יותר מוכר. כשאנחנו משתמשים ב-new או ב-constructor, אנחנו מפעילים את כל קטע הקוד בתוך הפונקציה o. אם נסתכל על ה-__proto__ של myMethod, אנחנו נראה שהוא של o ומכיל את myMetho אבל לא את a או את b כלומר כל שינוי שנעשה בהם ב-o לא יחלחל ל-myObj אחרי שעשינו new. אבל אם נעשה שינוי ב-myMethod הוא יחלחל כמובן לכולם. אלא אם כן אני אדרוס אותו.

שימוש ב-constructor של new
שימוש ב-constructor של new

אפשר לסכם את זה שכשאנחנו עושים


myObj = new o();

אנחנו עושים משהו כזה:


var myObj = new Object();
myObj.__proto__ = o.prototype;
o.call(myObj);

ה-call באובייקט הוא call של ג'אווהסקריפט שעליו דיברתי במאמרים קודמים. מדובר בהפעלה של o עם קביעה של ה-this שיהיה בדיוק כמו זה של myObj.

אני יודע שהמאמר הזה נראה די תיאורטי, אבל ככל שאנחנו משתמשים יותר בפריימוורקים מורכבים, לתיאוריה הזו יש חשיבות. כשאנחנו משתמשים בירושות של scope באנגולר או במקומות אחרים מאוד קל לשבור את הראש על בעיות של חלחול מה-__proto__ בלי להבין מאיפה הדברים מגיעים. הבנה תיאורטית של דרך ההתנהגות של ג'אווהסקריפט ועל ה-prototype chain היא קריטית לכל מפתח.

כדאי תמיד להשאר מעודכנים! אם יש לכם טלגרם, בדקו את ערוץ הטלגרם של האתר שבו אני מעדכן על פוסטים חדשים 🙂 אם אתם רוצים ללמוד תכנות באופן מקיף ומסודר, הצטרפו לאלפי הלומדים בפרויקט "ללמוד ג'אווהסקריפט בעברית" שמלמד לתכנת בג'אווהסקריפט, ב-Node.js ובריאקט וגם מלמד על תרומה לקוד פתוח. גם ספרים דיגיטליים וגם ספרים מודפסים. בשיתוף הקריה האקדמית אונו ובתמיכת חברות מובילות כגון Wix, Outbrain, Elementor, Iron Source, Chegg, Really Good ועוד.
JavaScript

תגובה אחת

  1. רוני שרר הגב ספטמבר 18, 2016 בשעה 10:37 am

    חסר בעיני הסבר על ההבדל בין:
    function o() {this.a = 1;this.b = 2;}
    o.prototype.myMethod = function() {return this.a + this.b;}
    ל:
    function o() {
    this.a = 1;this.b = 2;
    this.myMethod = function() {return this.a + this.b;}
    }

השארת תגובה

ביטול

ללמוד ג'אווהסקריפט בעברית

ללמוד לתכנת ג'אווהסקריפט בעברית שגייס יותר משלוש מאות אלף שקל ולמעלה מ-2000 תומכים - בואו ללמוד עכשיו איך לתכנת.

רשימת הנושאים
  • מדריכים
    • ריאקט
    • טייפסקריפט
    • ECMAScript 6
    • ES20XX
    • Node.js
    • Express
    • רספברי פיי
    • Babel
    • docker
    • MongoDB
    • Git
    • לימוד MySQL
    • SASS
    • jQuery
    • CSS3
    • HTML 5
    • SVN
    • LESS
  • פיתוח אינטרנט
    • פתרונות ומאמרים על פיתוח אינטרנט
    • jQuery Scripts
    • jQuery למתקדמים
    • יסודות בתכנות
    • נגישות אינטרנט
  • חדשות אינטרנט
  • מידע כללי על אינטרנט
    • רשת האינטרנט
    • בניית אתרי אינטרנט
  • rss logo

    לכל המאמרים

    לכל המאמרים שפורסמו באינטרנט ישראל משנת 2008 ועד עכשיו.
  • rss logo

    RSS Feed

    משתמשים בקורא RSS? אם כן, עקבו אחרי אינטרנט ישראל באמצעות פיד ה-RSS!
    מה זה RSS?
  • Twitter logo

    עקבו אחרי בטוויטר

    בחשבון הטוויטר שלי אני מפרסם עדכונים מהירים על חדשות בתחום התכנות והיזמות, התרעות על מצבי חירום ורכילות בוערת על תחום הווב.
    מה זה טוויטר?
  • facebook like image

    ערוץ הטלגרם של אינטרנט ישראל

    בערוץ הטלגרם של אינטרנט ישראל אני מפרסם את הפוסטים של באתר וכן עדכונים טכנולוגיים נוספים.
    מה זה טלגרם?
  • github logo

    הפרויקטים שלי בגיטהאב

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

כל הזכויות שמורות לרן בר-זיק ולאינטרנט ישראל | מדיניות הפרטיות של אתר אינטרנט ישראל | אתר אינטרנט ישראל נגיש לפי תקן WCAG 2.0 AA | הצהרת הנגישות של האתר | אבטחת מידע ודיווח על בעיית אבטחת מידע

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