prototype JavaScript
-
בקצרה: prototype זה מאפיין של פונקציות (בנאי אובייקטים) שמאפשר להרחיב את האובייקט שייווצר מהnew שלהם.
_proto_ זה מאפיין של מופעים (ערך שנוצר מnew) שנותן את ההרחבה שהוצמדה ע"י הprototype דלעיל.באריכות:
כמו בשפות OOP גם בJS יש מחלקות (types = טיפוסים, זה בעצם המקביל של class שיש בשפות הOOP וגם בJS ES6).
המשמעות של מחלקה זה תבנית שניתן ליצור ממנה מופעים, כמו תבנית עוגה, העוגות זה מופעים של התבנית. בJS נקרא לתבנית type ולעוגה object.
איך יוצרים טיפוס בJS? כותבים פונקציה. מה שהיא מחזירה, או הthis שלה זה יהיה המופע של הnew שקורא לה.function newType() { } var instance = new newType();
כעת עם אני רוצה להוסיף תכונות לטיפוס (ואני לא רוצה לשנות את הפונקציה newType, ראו בהמשך למה), כלומר לא למופע מסויים (כדגומת הinstance), אלא לכל המופעים שיווצרו מהnewType מכאן ולהבא,
אני יכול להציב במאפיין prototype למשל מאפיין או מתודה חדשים:newType.prototype = {newMethod: function() { return "pshhhh!"; }}; var instance2 = new newType(); instance2.newMethod(); // return "pshhhh!" instance.newMethod(); // throw error: instance.newMethod is not a function
האובייקט שהכנסנו בprototype נצמד לnewType ולכל מופע חדש, רק מכאן ולהבא, שייווצר ממנו יהיה את המתודה newMethod.
כעת שיש לנו ביד שתי אובייקטים, instance וinstance2. איך נוכל לדעת מי מהם מחזיק מתודה חדשה או כל תוכנה אחרת מעבר למה שיש בnewType? פה מגיע לעזרתנו ה__proto__. במאפיין הזה יש לנו גישה ל"תת האובייקט" שהוצמד ע"י הprototype שהוצב בטיפוס היוצר שלו.
למה שנרצה להוסיף אלמנטים לטיפוס דרך prototype ולא פשוט לשנות את פונקציית הבנאי שתכיל גם את האלמנטים הללו?
התשובה הראשונה שעולה היא - כי איננ יכולים לשנות את המקור, זה בכלל ספרייה של JS אחרת או אובייקט של הדפדפן/JS!
זו תשובה שגויה לפחות מבחינת המטרה, לא בגלל זה פיתחו את הprototype. הסיבה היא מטרה הפוכה, אנחנו רוצים להעתיק התנהגות של מחלקה מסויימת למחלקה שלנו. כלומר יש מחלקה כמו String או Date ואנו רוצים להרחיב אותה במאפיין או שתיים.
בשפות OOP עושים מה שנקרא ירושה. ובJS, עושים השמה של המוריש לprototype של היורש, ככה:newType.prototype = Date; // פה ניתן להציב כל טיפוס var instance = new newType(); instance.now();
בJS כמו בJS, יש עוד כל מיני רווחים צדדיים בשימוש בprototype.
כשיש לנו כזו שרשרת ירושה של מחלקה C שיורשת מB שהיא יורשת מA, נוכל לדעת זאת ע"י גישה למופע של C,
instanceOfC.__proto__.__proto__; // A function
אני חייב לציין שאינני מבין את הדברים לעומקן כלל (ואני גאה בזה ) וממילא אני מעודד מי שרואה אי דיוקים להדגישם, להאיר ולהעיר.
קראתי למשל באינטרנט שprotoype זה ירושה דינמית, כלומר זה לא באמת נמצא בכל מופע שניצור אלא שהדפדפן חופר בprotoype כדי להוציא משם חברים שלא קיימים בטיפוס הנוכחי, וממילא יש לזה עדיפות על הוספת איבר בטיפוס המקור שמשוכפל לכל מופע שייווצר. אני לא הבנתי למה בהוספת איבר בטיפוס המקורי יש שכפול מעבר לפרוטוטייפ. -
@מיכל אמר בprototype JavaScript:
העריכה האוטומטית שינתה לי משהוא ולא ראיתי שאפשר לערוך הודעה...
הכוונה מה ההבדל בין prototype ו __ proto __אפשר לערוך עם שלושת הנקודות האנכיות בצד שמאל למטה של ההודעה.
בקשר ל__, אכן בעיה. חיפשתי ומאצתי שסלש לפני כל קו תחתי מבטל את השפעתו העיצובית. אז ככה:\_\_proto__
-
מצגת יפה מאוד שמסבירה את ענין פרוטוטייפ ודיס (לא זוכר אם עונה ספציפית על השאלה הפותחת).
https://magicode.me/send-file/file/a427ee9a5b3eaba948c747fe9b9b4859de2d7b95/view
הורדתי א"ז מלינק שהביאו בפורום הישן.@dovid יש דרך להעלת א"ז לכאן בקביעות או אולי תצליח למצוא את הלינק המקורי?