diff options
Diffstat (limited to 'files/he/learn/javascript/objects/inheritance/index.html')
-rw-r--r-- | files/he/learn/javascript/objects/inheritance/index.html | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/files/he/learn/javascript/objects/inheritance/index.html b/files/he/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..1d43d06d14 --- /dev/null +++ b/files/he/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,437 @@ +--- +title: Inheritance in JavaScript +slug: Learn/JavaScript/Objects/Inheritance +translation_of: Learn/JavaScript/Objects/Inheritance +--- +<div dir="rtl">{{LearnSidebar}}</div> + +<div dir="rtl">{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div> + +<p class="summary" dir="rtl">לאחר שסיימנו עם התיאוריה והפרטים של OOJS, המאמר הזה נועד להראות כיצד ליצור מחלקות אובייקטים ״ילדים״ (constructors) אשר יורשים מההורים שלהם. אנו גם נציג מעין עצות מתי נרצה להשתמש ב-OOJS ונסתכל כיצד ״מחלקות״ מתבצעות בסינטקס המודרני של ECMAScript.</p> + +<table class="learn-box standard-table" dir="rtl"> + <tbody> + <tr> + <th scope="row">ידע מוקדם:</th> + <td> + <p>אוריינות מחשב בסיסית, הבנה בסיסית ב-HTML ו ב-CSS, היכרות עם יסודות ה-JavaScript (ראה <a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>) and OOJS basics (see <a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>).</p> + </td> + </tr> + <tr> + <th scope="row">מטרה:</th> + <td>להבין כיצד זה אפשרי להחיל הורשה ב- JavaScript</td> + </tr> + </tbody> +</table> + +<h2 dir="rtl" id="Prototypal_inheritance">Prototypal inheritance</h2> + +<p dir="rtl">עד עכשיו ראינו קצת הורשה בפעולה - ראינו כיצד prototype chains עובדות וכיצד מתודות ופרופ׳ מורשים בהמשך השרשרת. אבל זה היה בעיקר עם פונקציות מובנות של הדפדפן. כיצד אנחנו יכולים ליצור אובייקט ב-JavaScript אשר יורש מאובייקט אחר?</p> + +<h2 dir="rtl" id="דוגמא">דוגמא:</h2> + +<p dir="rtl">ראשית, עשו עותק מקומי של <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">הקובץ</a> או ראו אותו כ<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">דף אינטרנט</a>. בקוד זה אתם תראו את ה-<code>Person()</code> constructor שהשתמשנו בו לאורך המודול, עם שינוי קל - הגדרנו רק את ה-properties בתוך ה-constructor.</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +};</pre> + +<p dir="rtl">כל המתודות <em>כולן</em> מוגדרות בתוך ה-constructor's prototype. לדוגמא:</p> + +<pre class="brush: js" dir="rtl">Person.prototype.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); +};</pre> + +<div class="note" dir="rtl"> +<p><strong>לתשומת לבך</strong>: בקוד המקור אתם גם תראו מתודות נוספות שמוגדרות, <code>()bio</code> ו-<code>()farewell</code>. אנחנו נראה בהמשך כיצד מתודות אלו יכולות להיות מורשות ל-constructors אחרים.</p> +</div> + +<p dir="rtl">נניח ואנחנו רוצים ליצור מחלקה של <code>Teacher</code>, כמו זו שהסברנו בתחילת המודול לגבי תכנות מונחה עצמים, ומחלקה זו יורשת את כל הפרופ׳ והמתודות של <code>Person</code>, אבל גם כוללת:</p> + +<ol dir="rtl"> + <li>ה- property החדש בשם <code>subject</code> — אשר יכיל את נושאי הלימוד שהמורה מלמד.</li> + <li>מתודה <code>()greeting</code> מעודכנת, אשר תהיה יותר רשמית מהמתודה <code>()greeting</code> הרגילה.</li> +</ol> + +<h2 dir="rtl" id="הגדרה_של_ה-constructor_function_בשם_Teacher">הגדרה של ה-constructor function בשם ()Teacher</h2> + +<p dir="rtl">הדבר הראשון שאנחנו צריכים לעשות הוא להגדיר את ה-constructor בשם <code>()Teacher</code> - הוסיפו את הקוד הבא מתחת לקוד הנוכחי:</p> + +<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) { + Person.call(this, first, last, age, gender, interests); + + this.subject = subject; +}</pre> + +<p dir="rtl">זה נראה מאוד דומה ל-constructor בשם Person, אבל משהו פה שונה, משהו שלא ראינו עד כה - פונקציה בשם <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">()call</a></code>.</p> + +<p dir="rtl">פונקציה זו היא בעיקרון מאפשרת לנו לקרוא לפונקציה שהוגדרה במקום אחר, אבל לקרוא לה בהקשר הנוכחי.</p> + +<p dir="rtl">הפרמטר הראשון שהפונקציה הזו מקבלת מכיל את הערך של <code>this</code> שאנחנו נרצה להשתמש בו כאשר אנחנו מריצים את הפונקציה, והפרמטרים האחרים אלו פרמטרים שאמורים להיות מועברים לפונקציה עצמה כאשר היא מופעלת.</p> + +<p dir="rtl">אנחנו רוצים שה-<code>Teacher()</code> constructor יקבל את אותם פרמטרים כמו שה-<code>Person()</code> constructor שהוא יורש ממנו מקבל, ולכן אנחנו מציינים אותם כפרמטרים בתוך ההפעלה של ה-<code>()call</code>.</p> + +<p dir="rtl">השורה האחרונה בתוך ה-constructor פשוט מגדירה property בשם <code>subject</code> אשר ייחודי למורים, שאנשים רגילים מ-<code>()Person</code> לא מקבלים.</p> + +<p dir="rtl">יכלנו גם לרשום זאת כך, ללא שימוש ב-<code>()call</code>:</p> + +<pre class="brush: js" dir="rtl">function Teacher(first, last, age, gender, interests, subject) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.subject = subject; +}</pre> + +<p>אבל בקוד למעלה זו הגדרה מחדש של ה-properties כחדשים, לא כאלו שיורשים מ- <code>()Person</code>, אז זה סותר את מה שאנחנו מנסים לעשות - זה לא מוריש אלא זה יוצר חדשים. מה גם שזה לוקח יותר שורות קוד.</p> + +<h3 id="ירושה_מ-constructor_שלא_מקבל_פרמטרים">ירושה מ-constructor שלא מקבל פרמטרים</h3> + +<p>שימו לב שאם ה-constructor שאנחנו יורשים ממנו לא מקבל את הערכים של ה-property שלו מקבלים מפרמטרים, אז אנחנו לא צריכים לציין אותם כפרמטרים בתוך ה-<code>()call</code>. לדומא, אם היה לנו משהו פשוט כמו זה: :</p> + +<pre class="brush: js">function Brick() { + this.width = 10; + this.height = 20; +}</pre> + +<p>אנחנו יכולים לרשת את ה-properties של ה-<code>width</code> ואת ה-<code>height</code>, באמצעות שימוש בקוד הרשום מטה:</p> + +<pre class="brush: js">function BlueGlassBrick() { + Brick.call(this); + + this.opacity = 0.5; + this.color = 'blue'; +}</pre> + +<p>שימו לב שאנחנו רק צריכים לציין את ה-<code>this</code> בתוך ה-<code>()call</code>, ללא פרמטרים נוספים, שכן אנחנו לא יכולים יורשים שום דבר מ-<code>()Brick</code> שהוא קיבל דרך פרמטרים.</p> + +<h2 id="קביעת_ה-prototype_וה-constructor_של_Teacher">קביעת ה-prototype וה-constructor של ()Teacher</h2> + +<p>עד עכשיו הכל עובד תקין, אך יש לנו בעיה. הגדרנו אמנם constructor חדש, ויש לו את ה-property בשם <code>prototype</code>, אשר כברירת מחדל מכיל רק הפנייה ל-constructor function עצמה.</p> + +<p>הוא לא מכיל שום מתודות של ה-property בשם <code>prototype</code> של ה-Person constructor. על מנת לראות זאת, הכניסו <code>(Object.getOwnPropertyNames(Teacher.prototype</code> לתוך הקונסולה.</p> + +<p>לאחר מכן הכניסו זאת שוב, והחליפו את המילה <code>Teacher</code> במילה <code>Person</code>. ה-constructor החדש לא יורש את אותן מתודות. על מנת לראות זאת, השוו את הפלט של <code>Person.prototype.greeting</code> והפלט של <code>Teacher.prototype.greeting</code>. אנחנו צריכים לגרום ל-<code>()Teacher</code> לירוש מתודות שמוגדרות ב-prototype של <code>()Person</code>. איך עושים זאת?</p> + +<ol> + <li>הוסיפו את הקוד הבא מתחת לקוד שהוספתם לפני כן: + <pre class="brush: js">Teacher.prototype = Object.create(Person.prototype);</pre> + כאן <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">()create</a></code> מגיע שוב לעזרה. במקרה הזה, אנחנו משתמשים בו על מנת ליצור אובייקט חדש שיהיה הערך של <code>Teacher.prototype</code>. האובייקט החדש הוא בעל <code>Person.prototype</code> כאובייקט ה-prototype שלו, ולכן, הוא יירש ממנו אם וכאשר יצטרך, את כל המתודות שזמינות ב-<code>Person.prototype</code>.</li> + <li>אנחנו צריכים לעשות משהו נוסף לפני שנמשיך הלאה. לאחר שהוספנו את השורה הקודמת, ה-property בשם <code>constructor</code> שווה כעת ל- <code>()Person</code>, מכיוון שאנחנו הרגע הגדרנו את <code>Teacher.prototype</code> אליו. נסו לשמור את הקוד ולהעלות את הדף בדפדפן וראו זאת על ידי הקלדת <code>Teacher.prototype.constructor</code> בקונסולה.</li> + <li>זה יכול להיות בעיה, ולכן אנחנו צריכים לתקן זאת. ניתן לעשות זאת באמצעות הקלדת הקוד הבא מתחת לקוד הנוכחי שלנו.: + <pre class="brush: js">Object.defineProperty(Teacher.prototype, 'constructor', { + value: Teacher, + enumerable: false, // so that it does not appear in 'for in' loop + writable: true });</pre> + </li> + <li>כעת, אם תשמרו ותרעננו את הדף, הקלדת <code>Teacher.prototype.constructor</code> לקונסולה אמורה להחזיר לכם <code>()Teacher</code>, כפי שרצינו, ובנוסף אנחנו יורשים מ-<code>()Person</code>.</li> +</ol> + +<h2 id="הענקה_ל-_Teacher_פונקצייתמתודת_greeting_חדשה">הענקה ל- Teacher() פונקציית/מתודת greeting() חדשה</h2> + +<p>אנו רוצים להגדיר פונקציית <code>()greeting</code> חדשה בתוך ה-<code>Teacher()</code> constructor שלנו.</p> + +<p>הדרך הפשוטה ביותר לעשות זאת היא להגדיר זאת בתוך ה-prototype של <code>()Teacher</code> - הוסיפו את הקוד הבא מתחת לקוד הנוכחי:</p> + +<pre class="brush: js">Teacher.prototype.greeting = function() { + var prefix; + + if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') { + prefix = 'Mr.'; + } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') { + prefix = 'Mrs.'; + } else { + prefix = 'Mx.'; + } + + alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.'); +};</pre> + +<p>מתודה זו מקפיצה את הברכה של המורה, ומשתמשת במילים הנכונות בהתאם למין המורה באמצעות משפטי תנאי שהוגדרו.</p> + +<h2 id="נסו_את_הדוגמא_הבאה">נסו את הדוגמא הבאה:</h2> + +<p>כעת שהכנסו את כל הקוד, נסו ליצור אובייקטים חדשים מ-<code>()Teacher</code> באמצעות הכנסת הקוד הבא מתחת לקוד הנוכחי:</p> + +<pre class="brush: js">var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre> + +<p>כעת, שמרו את הדף ורעננו ונסו לגשת לפרופ׳ והמתודות של האובייקט <code>teacher1</code> החדש שלנו. לדוגמא:</p> + +<pre class="brush: js">teacher1.name.first; +teacher1.interests[0]; +teacher1.bio(); +teacher1.subject; +teacher1.greeting(); +teacher1.farewell();</pre> + +<p>הכל אמור לעבוד כשורה. השורות 1,2,3 ו-6 משתמשות במתודות/פרופ׳ שנורשו מה-<code>Person()</code> constructor שלנו. השורה 4 משתמשת בפרופ׳ שזמין רק באמצעות ה-<code>Teacher()</code> constructor שלנו. שורה 5 הייתה יכולה להיות מורשת מ-<code>()Person</code>, אבל מכיוון של-<code>()Teacher</code> יש את אותה מתודה, אז היא ניגשת למתודה שנמצאת ב-<code>()Teacher</code>.</p> + +<div class="note"> +<p><strong>לתשומת לב</strong>: אם נתקלתם בבעיות, נסו להשוות את הקוד שלכם ל <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">קוד הסופי</a> או ראו אותו כ <a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">דף אינטרנט</a>.</p> +</div> + +<p>הטכניקות שראינו עד כה, אינן היחידות ליצירת מחלקות ירושה ב-JavaScript, אבל הן עובדות בסדר, הן נותנות לכם הבנה כיצד להחיל ירושה ב-JavaScript.</p> + +<p>אולי תהיו מעוניינים לבדוק חלק מהאפשרויות החדשות ש-{{glossary("ECMAScript")}} מאפשרת לנו, בצורה ״נקייה״ יותר, באמצעות <a href="/en-US/docs/Web/JavaScript/Reference/Classes">Classes</a>. אנו נגע בדרך זו בהמשך. שימו לב כי דרך חדשה זו לא תומכת בכל הדפדפנים. כל יתר הדרכים שראינו תומכות בדפדנים ישנים גם כמו IE9 ומוקדם יותר ויש דרכים גם לאפשר תמיכה לדפדפנים ישנים יותר.</p> + +<p>דרך מקובלת היא להשתמש בספריית JavaScript - לפופולריות שביניהן יש סט של פונקציונליות שזמין עבור ביצוע הורשה בצורה פשוטה ומהירה. אחת מהן היא <a href="http://coffeescript.org/#classes">CoffeeScript</a> אשר מאפשרת <code>class</code> ,<code>extends</code> לדוגמא.</p> + +<h2 id="המשך_תרגול">המשך תרגול</h2> + +<p>במאמר שלנו בנושא <a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">OOP theory section</a>, כללנו גם מחלקת <code>Student</code> באופן עקרוני, אשר יורשת תכונות מ-<code>Person</code> וגם יש לה מתודת <code>()greeting</code> שונה מזו של <code>Person</code> ומשל <code>Teacher</code>. נסתכל כיצד ה-greeting של התלמידים אמורה להיות וננסה לבנות constructor בשם <code>()Student</code> משלנו, אשר יורש את כל התכונות מ-<code>()Person</code> ומחיל מתודת <code>()greeting</code> שונה.</p> + +<div class="note"> +<p><strong>שימו לב</strong>: אם אתם נתקלים בבעיות, ראו את ה<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-student.html">גרסה הסופית</a> או <a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">כדף אינטרנט</a> .</p> +</div> + +<h2 id="סיכום_בנושא_תכונות_האובייקט">סיכום בנושא תכונות האובייקט</h2> + +<p>על מנת לסכם, יש לנו בעיקרון שלוש סוגים של property/method לדאוג להם:</p> + +<ol> + <li>אלו המוגדרים בתוך ה-constructor function וניתנים לאובייקטים שנוצרים באמצעות ה- <code>this</code>. אלו בעיקרון מאוד קלים לאיתור - בתוך הקוד שלנו, אלו התכונות שמוגדרות בתוך ה-constructor באמצעות <code>this.x = x</code>, והם זמינים רק עבור האובייקטים שנוצרים (בדרך כלל נוצרים באמצעות ה-constructor ושימוש במילה השמורה <code>new</code>, לדוגמא: <code>()var myInstance = new myConstructor</code>.</li> + <li>אלו המוגדרים ישרות על ה-constructor עצמם, ואלו זמינות רק על ה-constructor. הם לרוב יהיו זמינים רק אובייקטים מובנים של הדפדפן, ואנחנו יכולים לזהות שהם קשורים באופן ישירות ל-constructor ולא למופע אובייקט. לדוגמא <code>()<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys</a></code>.</li> + <li>ואלו המוגדרים על הפרופ׳ בשם prototype של ה-constructor, אשר נורשים על ידי כל מופעי האובייקט שנוצרים או אובייקטים שיורשים מהם. זה כולל כל תכונה שמוגדרת ב-property בשם prototype של ה-Constructor. לדוגמא: <code>()myConstructor.prototype.x</code>.</li> +</ol> + +<p>אם אתם לא בטוחים מה זה מה, אל תדאגו, אתם תכירו אותם יותר לעומק במהלך הדרך והמשך הקריירה שלכם ככל שתתמודדו איתם.</p> + +<h2 id="ECMAScript_2015_Classes">ECMAScript 2015 Classes</h2> + +<p>ECMAScript 2015 הציגה מעין סינטקס חדש בשם <a href="/en-US/docs/Web/JavaScript/Reference/Classes">class syntax</a> ל- JavaScript כדרך חדשה לרשום מחלקות לשימוש חוזר, באמצעות סינטקס פשוט ונקי יותר, אשר דומה יותר ל-classes ב-C++ או ב-Java. בחלק הזה של המאמר אנחנו נמיר את הדוגמאות מלמעלה מ-prototypal inheritance ל-classes, על מנת להראות לכם איך לעשות שימוש-classes.</p> + +<div class="note"> +<p><strong>לתשומת לב</strong>: דרך חדשה זו של כתיבת classes נתמכת בכל הדפדפנים המודרניים, אבל זה עדיין חשוב להבין את ה-prototypal inheritance במקרה ותיתקלו בפרוייקט שדורש תמיכה בדפדפן שאינו תומך בסינטקס של classes - הידוע מבין כולם הוא Internet Explorer.</p> +</div> + +<p>נסתכל על הדוגמא שלנו של Person כתובה בצורת classes:</p> + +<pre class="brush: js">class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + greeting() { + console.log(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +} +</pre> + +<p>ההצהרה באמצעות המילה השמורה <a href="/en-US/docs/Web/JavaScript/Reference/Statements/class">class</a> מצהירה בעצם בשאנחנו רוצים ליצור class חדשה. בתוך הבלוק הזה שבין <code>{}</code>, אנחנו מגדירים את התכונות של אותה מחלקה:</p> + +<ul> + <li>המתודה <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/constructor">()constructor</a></code> מגדירה את ה-constructor function שמייצגת את ה-class <code>Person</code> שלנו.</li> + <li><code>()greeting</code> ו- <code>()farewell</code> הם class methods. כל מתודה שאנחנו נרצה לייחס אותה למחלקה מוגדרת בתוך ה-class, לאחר ה-constructor. בדוגמא הזו, השתמשנו ב- <a href="/en-US/docs/Web/JavaScript/Reference/Template_literals">template literals</a> מאשר בשרשור מחרוזות על מנת שהקוד שלנו יהיה קריא יותר.</li> +</ul> + +<p>כעת אנחנו יכולים ליצור מופעי אובייקט חדשים באמצעות שימוש באופרטור <a href="/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> operator</a>, באותה הדרך שעשינו בעבר:</p> + +<pre class="brush: js">let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']); +han.greeting(); +// Hi! I'm Han + +let leia = new Person('Leia', 'Organa', 19, 'female', ['Government']); +leia.farewell(); +// Leia has left the building. Bye for now +</pre> + +<div class="note"> +<p><strong>לתשומת לב</strong>: מאחורי הקלעים, ה-classes שלנו מומרים ל-prototypal Inheritance models - זהו רק syntactic sugar - שזה אומר דרך אחרת מבחינת סינטקס לעשות דבר זהה, אך לא משהו אחר. יחד עם זאת, אין ספק שזו דרך פשוטה יותר להעניק הורשה.</p> +</div> + +<h3 id="הורשה_עם_class_syntax">הורשה עם class syntax</h3> + +<p>למעלה יצרנו class על מנת לתאר person. יש לנו סט של תכונות שזהות לכל האנשים. בחלק זה אנחנו ניצור את ה-class המיוחד של <code>Teacher</code>, ונגרום לו לירוש מ-<code>Person</code> באמצעות שימוש בסינטקס class החדש. זה נקרא יצירת subclass או ביצוע subclassing.</p> + +<p>על מנת ליצור subclass אנחנו יכולים להשתמש במילה השמורה <a href="/en-US/docs/Web/JavaScript/Reference/Classes/extends">extends</a> על מנת להגיד ל-JavaScript איזו class אנחנו מתבססים עליה ביצירת ה-class החדשה:</p> + +<pre class="brush: js">class Teacher extends Person { + constructor(subject, grade) { + this.subject = subject; + this.grade = grade; + } +}</pre> + +<p>אך יש קאצ׳ קטן:</p> + +<p>שלא כמו ה-Constructor function, שבהן האופרטור <a href="/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> operator</a> היה עושה את האתחול של המילה <code>this</code> לאובייקט חדש, פה זה לא קורה בצורה אוטומטית בעבור המחלקה שמוגדרת באמצעות המילה <a href="/en-US/docs/Web/JavaScript/Reference/Classes/extends">extends</a>, כלומר עבור ה-sub-classes.</p> + +<p>ולכן הרצה שלהקוד למעלה יציג לנו שגיאה:</p> + +<pre class="brush: js">Uncaught ReferenceError: Must call super constructor in derived class before +accessing 'this' or returning from derived constructor</pre> + +<p>למחלקות משנה, sub-classes, ההגדרה של <code>this</code> בעבור אובייקט חדש, תהיה תמיד תלויה ב-parent class constructor, כלומר ב-constructor function של ה-class שממנה אנחנו מתרחבים (extending).</p> + +<p>כאן, אנחנו מרחיבים את המחלקה <code>Person</code>- המחלקת משנה בשם -<code>Teacher</code> היא בעצם extension - הרחבה - של המחלקה <code>Person</code>. אז עבור <code>Teacher</code> האתחול של <code>this</code> מתבצע על ידי ה-constructor <code>Person</code>.</p> + +<p>על מנת לקרוא ל-constructor ה-parent, אנחנו צריכים להשתמשש באופרטור <a href="/en-US/docs/Web/JavaScript/Reference/Operators/super"><code>()super</code> </a>, כך:</p> + +<pre class="brush: js">class Teacher extends Person { + constructor(subject, grade) { + super(); // Now `this` is initialized by calling the parent constructor. + this.subject = subject; + this.grade = grade; + } +}</pre> + +<p>אין שום סיבה שתהיה לנו sub-class אם היא לא יורשת מאפיינים מה-parent class.<br> + זה רעיון טוב אז שהאופרטור <a href="/en-US/docs/Web/JavaScript/Reference/Operators/super"><code>()super</code></a> גם מקבל ארגומנטים בעבור ה- parent constructor.</p> + +<p>כאשר אנחנו מסתכלים על ה- <code>Person</code> constructor, אנחנו יכולים לראות שיש לו את הבלוק קוד הבא בתוך ה-constructor שלו:</p> + +<pre class="brush: js"> constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +} </pre> + +<p>מאחר והאופרטור <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/super">()super</a></code> הוא בעצם ה-parent class constructor, העברה של הארגומנטים הרלוונטיים של המחלקת אם, גם תאתחל את הפרופ׳ במחלקת משנה שלנו, ותירש אותם: </p> + +<pre class="brush: js">class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + + // subject and grade are specific to Teacher + this.subject = subject; + this.grade = grade; + } +} +</pre> + +<p>כעת, כשיוצרים מופעי אובייקט של <code>Teacher</code>, אנחנו יכולים לקרוא למתודות ופרופ׳ שהוגדרו גם ב-<code>Teacher</code> וגם ב-<code>Person</code>:</p> + +<pre class="brush: js">let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5); +snape.greeting(); // Hi! I'm Severus. +snape.farewell(); // Severus has left the building. Bye for now. +snape.age // 58 +snape.subject; // Dark arts +</pre> + +<div class="note"> +<p><strong>לתשומת לב</strong>: אתם יכולים למצוא את הדוגמא ב-GitHub ב- <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-class-inheritance.html">es2015-class-inheritance.html</a> או כ-<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-class-inheritance.html">דף אינטרנט</a>.</p> +</div> + +<h2 id="Getters_ו-_Setters">Getters ו- Setters</h2> + +<p>יהיו פעמים שאנחנו נרצה לשנות את הערכים של מאפיין בתוך השאנחנו יוצרים או שאנחנו לא נדע מהו הערך הסופי שאותו מאפיין יקבל. אם נסתכל על הדוגמא שלנו <code>Teacher</code>, יכול להיות מצב שאנחנו לא נדע מה הנושא שהמורה מלמד לפני שאנחנו יוצרים אותו או שהנושא יכול להשתנות במהלך התקופה.</p> + +<p>במקרים כאלו אנחנו נוכל להשתמש ב-getters ו-setters.</p> + +<p>נשפר את Teacher class עם getters ו-setters. המחלקה מתחילה בדיוק כמו שראינו אותה בדוגמא האחרונה.</p> + +<p> getters ו-setters עובדים בזוגות. getter מחזיר את הערך הנוכחי של משתנה וה-setter הבן זוג שלו משנה את הערך של המשתנה למה שה-setter יגדיר. </p> + +<p>המחלקה <code>Teacher</code> החדשה תיראה כך:</p> + +<pre class="brush: js">class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + // subject and grade are specific to Teacher + this._subject = subject; + this.grade = grade; + } + + get subject() { + return this._subject; + } + + set subject(newSubject) { + this._subject = newSubject; + } +} +</pre> + +<p>במחלקה למעלה יש לנו getter ו-setter בעבור הפרופ׳ <code>subject</code>. אנחנו משתמשים בסימן <code>_</code> על מנת ליצור ערך נפרד שבו נאחסכן את השם של הפרופ׳. אם לא נעשה זאת בצורה הזה, אנחנו נקבל שגיאות בכל פעם שנקרא ל-get או ל-set. בנקודה זו: </p> + +<ul> + <li>על מנת לקבל את הערך הנוכחי של הפרופ׳ <code>_subject</code> של האובייקט <code>snape</code>, אנחנו יכולים להשתמש במתודת <code>snape.subject</code> getter.</li> + <li>על מנת להשים ערך חדש לפרופ׳ <code>_subject</code> אנחנו יכולים להשתמש במתודת <code>snape.subject="new value"</code> setter. </li> +</ul> + +<p>הדוגמא למטה מראה את השימוש באפשרויות האלו: </p> + +<pre class="brush: js">// Check the default value +console.log(snape.subject) // Returns "Dark arts" + +// Change the value +snape.subject="Balloon animals" // Sets _subject to "Balloon animals" + +// Check it again and see if it matches the new value +console.log(snape.subject) // Returns "Balloon animals" +</pre> + +<div class="note"> +<p><strong>לתשומת לב </strong>: תוכלו למצוא את <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-getters-setters.html">es2015-getters-setters.html</a> ב-GitHub, או כ<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-getters-setters.html">דף אינטרנט</a>.</p> +</div> + +<h2 id="מתי_אנחנו_נשתמש_בהורשה_ב-JavaScript">מתי אנחנו נשתמש בהורשה ב-JavaScript?</h2> + +<p>רוב הסיכויים שלאחר קריאת המאמר הזה, אתם בטח חושבים לעצמכם ״טוב, זה מסובך מאוד״. אתם צודקים. הורשה ואבי טיפוס הינם חלק מההיבטים המורכבים ביותר של JavaScript, אבל הרבה מעוצמתה של השפה והגמישות שלה מגיע מתוך המבנה של האובייקטים והירושה שלהם, וזה שווה להכיר ולהבין כיצד התהליכים הללו מתרחשים. </p> + +<p>בדרך מסויימת, אנחנו משתמשים בהורשה כל הזמן. בכל פעם שאנחנו משתמשים במאפיינים שונים של Web API או בפרופ׳/מתודות שהוגדרו באובייקט מובנה של הדפדפן (built-in browser object) על מחרוזות, מערכים וכד׳ אנחנו באופן עקיף משתמשים בירושה. </p> + +<p>במונחים של שימוש בירושה בקוד שלנו, אנחנו ככל הנראה לא נשתמש בזה באופן תדיר, במיוחד בהתחלה ובפרוייקטים קטנים. זה בזבוז זמן להשתמש באובייקטים וירושה רק לשם השימוש בהם אם אנחנו לא צריכים. אבל ככל שכמות הקוד גדלה, אנחנו ככל הנראה נזהה את הצורך להתחיל להשתמש בכך. םא אנחנו מוצאים את עצמנו מתחילים ליצור מספר אובייקטים שיש להם מאפיינים זהים, אז יצירת אובייקט גנרי אחד אשר יכיל את כל הפונקציונליות המשותפת של אותם אובייקטים ויוריש להם את אותה פונקציונליות תהיה דרך מאוד שימושית ונוחה.</p> + +<div class="note"> +<p><strong>לתשומת לב</strong>: לאור הדרך שבה JavaScript עובדת עם שרשרת אבי הטיפוס (prototype chain) וכד׳ - השיתוף של פונקציונליות בין אובייקטים נקרא לרוב <strong>delegation - ״האצלה״</strong>. אובייקטים מיוחדים ״מאצילים״ פונקציונליות לאובייקטים שנוצרים. </p> +</div> + +<p>כאשר אנחנו משתמשים בהורשה, ההמלצה היא שלא יהיו יותר מדי רמות של הורשה, ושתמיד נעקוב איפה אנחנו מגדירים את המתודות והפרופ׳. זה אפשרי להתחיל לכתוב קוד שבאופן זמני משנה את ה-prototypes של האובייקטים המובנים של הדפדפן (built-in browser objects), אבל אין לעשות זאת אלא אם כן יש לנו סיבה מאוד טובה. יותר מדי הורשה יכולה להוביל לבלבול אינסופי ולשגיאות בקוד. </p> + +<p>באופן אולטמטיבי, אובייקטים הם פשוט תבנית אחרת של שימוש חוזר בקוד, כמו פונקציות ולולאות, עם הכללים והיתרונות שלהם. אם אתם מוצאים את עצמכם יוצרים משתנים ופונקציות הקשורים אחד לשני ואתם רוצים לעקוב ולארוז אותם יחד בצורה מסודרת, אובייקט הוא רעיון טוב. אובייקטים גם שימושיים מאוד כשאנחנו רוצים להעביר ריכוז של מידע ממקום אחד למקום שני. את שני הדברים הללו ניתן להשיג ללא שימוש ב-constructors או ב-inheritance. אם אנחנו צריכים רק מופע אחד של אובייקט, כנראה יהיה עדיף פשוט להשתמש ב-inheritance ואין צורך בירושה.</p> + +<h2 id="אלטרנטיבות_להרחבה_של_שרשרת_ההורשה">אלטרנטיבות להרחבה של שרשרת ההורשה </h2> + +<p>ב-JavaScript, יש מספר דרכים שונות להרחבה של ה-prototype של אובייקט חוץ מאלו שראינו במאמר זה. להרחבה בנושא, ראו את הדף שלנו בנושא <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Different_ways_to_create_objects_and_the_resulting_prototype_chain">Inheritance and the prototype chain</a>.</p> + +<h2 id="לסיכום">לסיכום</h2> + +<p>מאמר זה נועד לסקור את יתרת הנושא של OOJS וסינטקס נוסף שאנחנו חושבים שאתם צריכים לדעת. בנקודה זו אתם אמורים להבין את ההיבטים של אובייקטים ב-JavaScript ואת הבסיס של תכנות מונחה עצמים (OOP), אביט טיפוס, שרשרת אבי-טיפוס, הורשה באמצעות אבי-טיפוס, כיצד ליצור מחלקות (classes), מופעי אובייקטים, הוספת מאפיינים למחלקות, יצירת מחלקות משנה שיורשות ממחלקות אחרות ועוד. </p> + +<p>במאמר הבא אנחנו נגע כיצד לעבוד עם (JavaScript Object Notation (JSON, פורמט מקובל להעברת מידע.</p> + +<h2 id="ראו_גם">ראו גם</h2> + +<ul> + <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — אתר ללמידה אינטראקטיבית של בנושא אובייקטים.</li> + <li><a href="https://www.manning.com/books/secrets-of-the-javascript-ninja-second-edition">Secrets of the JavaScript Ninja</a>, פרק 7 - ספר טוב בנושא עקרונות מתקדמים של JavaScript של John Resig, Bear Bibeault, ו-Josip Maras. פרק 7 מכסה את ההיבטים של אבי טיפוס והורשה. </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p> + +<h2 id="במודול_זה">במודול זה</h2> + +<ul> + <li><a href="/he/docs/Learn/JavaScript/Objects/Basics">אובייקטים - עקרונות יסוד</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript למתחילים</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/Inheritance">הורשה ב-JavaScript</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/JSON">עבודה עם JSON data</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/Object_building_practice">שיטות ליצירת אובייקטים</a></li> + <li><a href="/he/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> + <li></li> +</ul> |