From 1109132f09d75da9a28b649c7677bb6ce07c40c0 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:45 -0500 Subject: initial commit --- .../adding_bouncing_balls_features/index.html | 214 ++++++++++ .../he/learn/javascript/objects/basics/index.html | 257 ++++++++++++ files/he/learn/javascript/objects/index.html | 54 +++ .../javascript/objects/inheritance/index.html | 437 +++++++++++++++++++++ files/he/learn/javascript/objects/json/index.html | 346 ++++++++++++++++ .../objects/object-oriented_js/index.html | 275 +++++++++++++ .../objects/object_prototypes/index.html | 283 +++++++++++++ 7 files changed, 1866 insertions(+) create mode 100644 files/he/learn/javascript/objects/adding_bouncing_balls_features/index.html create mode 100644 files/he/learn/javascript/objects/basics/index.html create mode 100644 files/he/learn/javascript/objects/index.html create mode 100644 files/he/learn/javascript/objects/inheritance/index.html create mode 100644 files/he/learn/javascript/objects/json/index.html create mode 100644 files/he/learn/javascript/objects/object-oriented_js/index.html create mode 100644 files/he/learn/javascript/objects/object_prototypes/index.html (limited to 'files/he/learn/javascript/objects') diff --git a/files/he/learn/javascript/objects/adding_bouncing_balls_features/index.html b/files/he/learn/javascript/objects/adding_bouncing_balls_features/index.html new file mode 100644 index 0000000000..23197f00c4 --- /dev/null +++ b/files/he/learn/javascript/objects/adding_bouncing_balls_features/index.html @@ -0,0 +1,214 @@ +--- +title: Adding features to our bouncing balls demo +slug: Learn/JavaScript/Objects/Adding_bouncing_balls_features +translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}
+ +

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

+ + + + + + + + + + + + +
Prerequisites:Before attempting this assessment you should have already worked through all the articles in this module.
Objective:To test comprehension of JavaScript objects and object-oriented constructs
+ +

Starting point

+ +

To get this assessment started, make a local copy of index-finished.html, style.css, and main-finished.js from our last article in a new directory in your local computer.

+ +

Alternatively, you could use a site like JSBin or Glitch to do your assessment. You could paste the HTML, CSS and JavaScript into one of these online editors. If the online editor you are using doesn't have separate JavaScript/CSS panels, feel free to put them inline <script>/<style> elements inside the HTML page.

+ +
+

Note: If you get stuck, then ask us for help — see the {{anch("Assessment or further help")}} section at the bottom of this page.

+
+ +

Hints and tips

+ +

A couple of pointers before you get started.

+ + + +

Project brief

+ +

Our bouncy ball demo is fun, but now we want to make it a little bit more interactive by adding a user-controlled evil circle, which will eat the balls if it catches them. We also want to test your object-building skills by creating a generic Shape() object that our balls and evil circle can inherit from. Finally, we want to add a score counter to track the number of balls left to capture.

+ +

The following screenshot gives you an idea of what the finished program should look like:

+ +

+ + + +

To give you more of an idea, have a look at the finished example (no peeking at the source code!)

+ +

Steps to complete

+ +

The following sections describe what you need to do.

+ +

Creating our new objects

+ +

First of all, change your existing Ball() constructor so that it becomes a Shape() constructor and add a new Ball() constructor:

+ +
    +
  1. The Shape() constructor should define the x, y, velX, and velY properties in the same way as the Ball() constructor did originally, but not the color and size properties.
  2. +
  3. It should also define a new property called exists, which is used to track whether the balls exist in the program (have not been eaten by the evil circle). This should be a boolean (true/false).
  4. +
  5. The Ball() constructor should inherit the x, y, velX, velY, and exists properties from the Shape() constructor.
  6. +
  7. It should also define a color and a size property, like the original Ball() constructor did.
  8. +
  9. Remember to set the Ball() constructor's prototype and constructor appropriately.
  10. +
+ +

The ball draw(), update(), and collisionDetect() method definitions should be able to stay exactly the same as they were before.

+ +

You also need to add a new parameter to the new Ball() ( ... ) constructor call — the exists parameter should be the 5th parameter, and should be given a value of true.

+ +

At this point, try reloading the code — it should work just the same as it did before, with our redesigned objects.

+ +

Defining EvilCircle()

+ +

Now it's time to meet the bad guy — the EvilCircle()! Our game is only going to involve one evil circle, but we are still going to define it using a constructor that inherits from Shape() to give you some practice. You might want to add another circle to the app later on that can be controlled by another player, or have several computer-controlled evil circles. You're probably not going to take over the world with a single evil circle, but it will do for this assessment.

+ +

The EvilCircle() constructor should inherit x, y, velX, velY, and exists from Shape(), but velX and velY should always equal 20.

+ +

You should do this something like Shape.call(this, x, y, 20, 20, exists);

+ +

It should also define its own properties, as follows:

+ + + +

Again, remember to define your inherited properties as parameters in the constructor, and set the prototype and constructor properties correctly.

+ +

Defining EvilCircle()'s methods

+ +

EvilCircle() should have four methods, as described below.

+ +

draw()

+ +

This method has the same purpose as Ball()'s draw() method: It draws the object instance on the canvas. It will work in a very similar way, so you can start by copying the Ball.prototype.draw definition. You should then make the following changes:

+ + + +

checkBounds()

+ +

This method will do the same thing as the first part of Ball()'s update() function — look to see whether the evil circle is going to go off the edge of the screen, and stop it from doing so. Again, you can mostly just copy the Ball.prototype.update definition, but there are a few changes you should make:

+ + + +

setControls()

+ +

This method will add an onkeydown event listener to the window object so that when certain keyboard keys are pressed, we can move the evil circle around. The following code block should be put inside the method definition:

+ +
let _this = this;
+window.onkeydown = function(e) {
+    if (e.key === 'a') {
+      _this.x -= _this.velX;
+    } else if (e.key === 'd') {
+      _this.x += _this.velX;
+    } else if (e.key === 'w') {
+      _this.y -= _this.velY;
+    } else if (e.key === 's') {
+      _this.y += _this.velY;
+    }
+  }
+ +

So when a key is pressed, the event object's keyCode property is consulted to see which key is pressed. If it is one of the four represented by the specified keycodes, then the evil circle will move left/right/up/down.

+ +

For a bonus point, can you tell us why we've had to set let _this = this; in the position it is in? It is something to do with function scope.

+ +

collisionDetect()

+ +

This method will act in a very similar way to Ball()'s collisionDetect() method, so you can use a copy of that as the basis of this new method. But there are a couple of differences:

+ + + +

Bringing the evil circle into the program

+ +

Now we've defined the evil circle, we need to actually make it appear in our scene. To do this, you need to make some changes to the loop() function.

+ + + +

Implementing the score counter

+ +

To implement the score counter, follow the following steps:

+ +
    +
  1. In your HTML file, add a {{HTMLElement("p")}} element just below the {{HTMLElement("h1")}} element containing the text "Ball count: ".
  2. +
  3. In your CSS file, add the following rule at the bottom: +
    p {
    +  position: absolute;
    +  margin: 0;
    +  top: 35px;
    +  right: 5px;
    +  color: #aaa;
    +}
    +
  4. +
  5. In your JavaScript, make the following updates: +
      +
    • Create a variable that stores a reference to the paragraph.
    • +
    • Keep a count of the number of balls on screen in some way.
    • +
    • Increment the count and display the updated number of balls each time a ball is added to the scene.
    • +
    • Decrement the count and display the updated number of balls each time the evil circle eats a ball (causes it not to exist).
    • +
    +
  6. +
+ + + +

Assessment or further help

+ +

If you would like your work assessed, or are stuck and want to ask for help:

+ +
    +
  1. Put your work into an online shareable editor such as CodePen, jsFiddle, or Glitch.
  2. +
  3. Write a post asking for assessment and/or help at the MDN Discourse forum Learning category. Your post should include: +
      +
    • A descriptive title such as "Assessment wanted for Adding bouncing balls features".
    • +
    • Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.
    • +
    • A link to the example you want assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.
    • +
    • A link to the actual task or assessment page, so we can find the question you want help with.
    • +
    +
  4. +
+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}

+ +

In this module

+ + diff --git a/files/he/learn/javascript/objects/basics/index.html b/files/he/learn/javascript/objects/basics/index.html new file mode 100644 index 0000000000..25c439e43d --- /dev/null +++ b/files/he/learn/javascript/objects/basics/index.html @@ -0,0 +1,257 @@ +--- +title: JavaScript object basics +slug: Learn/JavaScript/Objects/Basics +translation_of: Learn/JavaScript/Objects/Basics +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}
+ +

במאמר בזה, אנחנו נסתכל על עקרונות הסינטקס הבסיסים של אובייקטים ב-JavaScript, ונבקר בחלק ממאפייניה של השפה שנתקלנו בה בעבר, ונבין כי חלק ממאפיינים אלו הם בעצם אובייקטים.

+ + + + + + + + + + + + +
Prerequisites:Basic computer literacy, a basic understanding of HTML and CSS, familiarity with JavaScript basics (see First steps and Building blocks).
מטרה:הבנת התיאוריה הבסיסית שעומדת מאחורי תכנות מונחה עצמים, כיצד זה מתקשר ל-JavaScript (״רוב הדברים הם אובייקטים״) והבנה כיצד ניתן לעבוד עם אובייקטים ב-JavaScript.
+ +

Object - אובייקטים - עקרונות יסוד

+ +

אובייקט הוא אוסף של מידע או פונקציונליות (בדרך מכיל מספר של מתשנים ופונקציות, אשר נקראים - מאפיינים (properties) ו-מתודות (Methodes) כאשר ה נמצאים בתוך אובייקט). נסתכל על דוגמא על מנת להמחיש את הנושא.

+ +

על מנת להתחיל, הכינו עותק מקומי של oojs.html. קובץ זה מכיל אלמנט של {{HTMLElement("script")}} על מנת שבתוכו נכתוב את הקוד שלנו. אנחנו נשתמש בתצורה הזו על מנת להבין את הסינטקס הבסיסי של אובייקטים. יד עם קובץ זה, פתחו את developer tools JavaScript console.

+ +

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

+ +
const person = {};
+ +

כעת פתחו את הקונסולה בדפדפן והזינוו person בתוך הקונסולה, ולאחר מכן לחצו על , Enter/Return. אתם אמורים לקבל תוצאה שנראית כך:

+ +
[object Object]
+Object { }
+{ }
+
+ +

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

+ +
const person = {
+  name: ['Bob', 'Smith'],
+  age: 32,
+  gender: 'male',
+  interests: ['music', 'skiing'],
+  bio: function() {
+    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
+  },
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name[0] + '.');
+  }
+};
+
+ +

לאחר שמירה ורענון של הדף, נסו להכניס את השורות הבאות לתוך הקונסולה:

+ +
person.name
+person.name[0]
+person.age
+person.interests[1]
+person.bio()
+person.greeting()
+ +

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

+ +
+

לתשומת לב: אם אינכם מצליחים לגרום לכך לעבוד, נסו להשוות אל מול הקובץ שלנו oojs-finished.html או ראו את דף האינטרנט ופתחו את הקונסולה בדף זה

+
+ +

אובייקט מורכב ממספר רכיבים, כאשר לכל רכיב יש שם   (name ו- age למעלה), וכן יש לכל רכיב value (e.g. ['Bob', 'Smith'] ו- 32). כל צמד של שם/ערך חייב להיות מופרד באמצעות פסיק , והשם והערך בכל צמד חייבים להיות מופרדים עם :. הסינטקס תמיד ייראה בתבנית הזו:

+ +
const objectName = {
+  member1Name: member1Value,
+  member2Name: member2Value,
+  member3Name: member3Value
+};
+ +

הערך של אובייקט יכול להיות כל דבר - במקרה שלנו, האובייקט person, יש לנו מחרוזת, מספר, שני מערכים, ושתי פונקציות. ארבעת הצמדים הראשונים הם פריטי מידע והם נקראים כ-properties של האובייקט. שני הצמדים האחרונים אלו פונקציות שמאפשרות לאובייקט לעשות משהו עם המידע הזה, והם נקראים ה-methods של האובייקט.

+ +

אובייקט כמו זה נקרא object literal — אנחנו באופן ליטראלי )מפורש) יצרנו את האובייקט והתוכן שלו. זה בניגוד לאובייקטים שנוצרו ממחלקות (classs) שאשר נראה בהמשך.

+ +

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

+ +

Dot notation שימוש בנקודה-

+ +

למעלה, אנחנו יכולים לגשת למתודות ולפרופ׳ של האובייקט באמצעות dot notation. שם האובייקט - person - משמש כ-namespace - הוא חייב להיות מוכנס ראשון, על מנת לקבל גישה לכל מה שמוכס - encapsulated בתוך האובייקט. לאחר מכן אנחנו רושמים נקודה . ואז את הפריט מידע שאנחנו רוצים לגשת אליו - זה יכול שם של פרופ׳ מסויים, או לקרוא לאחת מהמתודות של האובייקט. לדוגמא:

+ +
person.age
+person.interests[1]
+person.bio()
+ +

Sub-namespaces

+ +

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

+ +
name: ['Bob', 'Smith'],
+ +

לקוד זה:

+ +
name : {
+  first: 'Bob',
+  last: 'Smith'
+},
+ +

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

+ +
person.name.first
+person.name.last
+ +

חשוב: לאחר שינוי זה אתם צריכים גם לשנות במתודות את צורת הכתיבה לאור כך ששינינו את הערך ממערך לאובייקט

+ +
name[0]
+name[1]
+ +

לתצורה הבאה:

+ +
name.first
+name.last
+ +

אחרת המתודות לא יעבדו.

+ +

Bracket notation - שימוש בסוגריים מרובעות

+ +

יש דרך נוספת לגשת לפרופ׳ של האובייקט - באמצעות שימוש בסוגריים מרובעות. במקום הקוד הבא:

+ +
person.age
+person.name.first
+ +

אנחנו יכולים להשתמש בקוד זה:

+ +
person['age']
+person['name']['first']
+ +

זה אמנם נראה מאוד דומה לדרך שבה אנחנו ניגשים לאיברים במערך, ובעיקרון זה אותו דבר - אך במקום להשתמש במספר אינדקס על מנת לבחור איבר מסויים, כפי שנאחנו עושים במערך, אנחנו משתמשים בשם המקושר לכל ערך. זה לא פלא שלפעמים אובייקטים נקראים associative arrays — they map strings to values in the same way that arrays map numbers to values.

+ +

הגדרת מפתחות ומתודות לאובייקט -

+ +

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

+ +
person.age = 45;
+person['name']['last'] = 'Cratchit';
+ +

נסו להזין את השורות למעלה ואז לגשת לערכים ששיניתם באמצעות הקוד על מנת לראות השינוי:

+ +
person.age
+person['name']['last']
+ +

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

+ +
person['eyes'] = 'hazel';
+person.farewell = function() { alert("Bye everybody!"); }
+ +

וכעת בדקו את המפתח והמתודה החדשה כך:

+ +
person['eyes']
+person.farewell()
+ +

היבט מאוד שימושי של שימוש בסוגריים מרובעות הוא שזה לא רק מאפשר לנו לקבוע את הערכים של אותו פריט בצורה דינאמית, אלא גם את השם של אותו פרופ׳ . נניח שאנחנו רוצים שהמשתמשים יוכלו לאחסן ערכים שונים בתוך המידע, באמצעות One useful aspect of bracket notation is that it can be used to set not only member values dynamically, but member names too. Let's say we wanted users to be able to store custom value types in their people data, by typing the member name and value into two text inputs. We could get those values like this:

+ +
let myDataName = nameInput.value;
+let myDataValue = nameValue.value;
+ +

We could then add this new member name and value to the person object like this:

+ +
person[myDataName] = myDataValue;
+ +

To test this, try adding the following lines into your code, just below the closing curly brace of the person object:

+ +
let myDataName = 'height';
+let myDataValue = '1.75m';
+person[myDataName] = myDataValue;
+ +

Now try saving and refreshing, and entering the following into your text input:

+ +
person.height
+ +

הוספת פרופ׳ לאובייקט באמצעות המתודה לעיל אינה אפשרית כאשר אנחנו משתמשים ב-dot notation, כי היא מקבלת רק ערך ליטרלי ולא ערך של משתנה מסויים שמצביע על אותו שם.

+ +

מה זה "this"?

+ +

אולי שמתם לב למשהו קצת מוזר בתוך המתודות שלנו. ראו את הדוגמא הבאה:

+ +
greeting: function() {
+  alert('Hi! I\'m ' + this.name.first + '.');
+}
+ +

אתם בטח שואלים את עצמכם מה זה "this". המילה השומרה this מתייחסת לאובייקט שהקוד נכתב בתוכו - אז במקרה הזה המילה this שווה ל- person. אז מדוע לא לרשום person במקום? כפי שתראו במאמר שלנו בנושאObject-oriented JavaScript מתחילים - כאשר אנחנו יוצרים קונסטרקטורים, המילה this היא מאוד שימושית - היא תבטיח לנו תמיד שהערכים הנכונים מושמים בכל פעם שהמופעים של האובייקט פפפפפ נוצרים - גלומר - אובייקטים שנוצרו - 999999, יהיו בעלי ערכים שונים article, when we start creating constructors and so on, this is very useful — it will always ensure that the correct values are used when a member's context changes (e.g. two different person object instances may have different names, but will want to use their own name when saying their greeting).

+ +

ננסה לפשט ולהסביר באמצעות יצירת שני אובייקטים של person:

+ +
const person1 = {
+  name: 'Chris',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+
+const person2 = {
+  name: 'Brian',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+ +

במקרה הזה, person1.greeting() יציג "Hi! I'm Chris.";ואילו person2.greeting() יציג "Hi! I'm Brian.", למרות שהקוד של המתודה הוא זהה לחלוטין. כפי שאמרנו למעלה, this שוה בעצם לאובייקט שהקוד נמצא בתוכו - this לא משמעותי ושימושי כאשר אנחנו יוצרים אובייקטים באמצעות אובייקט ליטראלי, אבל הוא מאוד שימושי כאשר אנחנו יוצרים אובייקטים באופן דינאמי (באמצעות קונסטרקטורים לדוגמא). זה יהיה ברור יותר בהמשך הדרך, מבטיחים.

+ +

השתמשנו באובייקטים לאורך כל הזמן הזה

+ +

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

+ +

כאשר אנחנו משתמשים במתודות של מחרוזות כאלו לדוגמא:

+ +
myString.split(',');
+ +

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

+ +

כאשר אנחנו ניגשים ל-document object model אמצעות הקוד הבא:

+ +
const myDiv = document.createElement('div');
+const myVideo = document.querySelector('video');
+ +

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

+ +

אותו הדבר בערך קורה עם הרבה אובייקטים מובנים/api שאנחנו משתשמים בהם — Array, Math, וכך הלאה.

+ +

שימו לב שbuilt in Objects/APIs לא תמיד יוצרים מופעים של אובייקט באופן אוטומטי. לדוגמא, ה- Notifications API — אשר מאפשר לדפדפנים מודרניים להזרים התראות מערת - דורש מאיתנו לייצר מופע אובייקט חדש באמצעות קונסטקטור, עבור כל התראה שנרצה להזרים. נסו להזין את הקוד הבא בקוסולה: :

+ +
const myNotification = new Notification('Hello!');
+ +

אנו נסתכל על קונסרקטורים במאמרים הבאים.

+ +
+

לתשומת לב: זה מאוד שימושי לחשוב על הדרך שבה אובייקטים מתקשרים כ- message passing — כאשר אובייקט אחד צריך אובייקט אחד על מנת לבצע פעולה מסויימת, הוא לרוב ישלח הודעה לאותו אובייקט באמצעו תאחת המתודות שלו ויחכה לתגובה, שהיא בעצם ה- return value.

+
+ +

לסיכום

+ +

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

+ +

במאמר הבא אנחנו נסתכל על תיאוריית object-oriented programming (OOP), וכיצד טכניקות שכאלו יכולות לשמש אותנו ב- JavaScript.

+ +

{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}

+ +

במודול זה

+ + diff --git a/files/he/learn/javascript/objects/index.html b/files/he/learn/javascript/objects/index.html new file mode 100644 index 0000000000..3b033ee0e8 --- /dev/null +++ b/files/he/learn/javascript/objects/index.html @@ -0,0 +1,54 @@ +--- +title: Introducing JavaScript objects +slug: Learn/JavaScript/Objects +tags: + - Article + - Assessment + - Beginner + - CodingScripting + - Guide + - JavaScript + - Learn + - NeedsTranslation + - Objects + - TopicStub + - Tutorial +translation_of: Learn/JavaScript/Objects +--- +
{{LearnSidebar}}
+ +

ב-JavaScript, רוב הדברים הם אובייקטים, החל מהמאפיינים הבסיסיים של השפה כמו מחרוזות ומערכים, ועד {{Glossary("API", "APIs")}} של הדפדפן שבנויים מעל JavaScript. אנחנו אפילו יכולים ליצור אובייקטים בעצמנו, ו-״להכמיס״ בתוכן פונקציות ומשתנים כך שיתפקדו ככלי להכלת מידע מאוד שימושי. חשוב להבין את הרעיון של JavaScript סביב האובייקט אם אנחנו רוצים להמשיך להתקדם בלמידה שלנו של שפה זו, ומודול זה נועד בדיוק לשם כך. במודול זהנלמד על התיאוריה סביב אובייקט וכן על הסינטקס בפרטים ומשם נמשיך ליצירת אובייקטים בעצמנו

+ +

ידע מוקדם

+ +

לפני שתחלו בלימוד מודול זה, ודאו כי אתם בקיאים ב- {{Glossary("HTML")}} וב- {{Glossary("CSS")}}. אנו ממליצים לכם לעבור על המודולים בנושא הכרות עם HTML ו-הכרות עם CSS לפני שתמשיכו בלימוד JavaScript.

+ +

בנוסף, הנכם מתבקשים לעבור על עקרונות הבסיס של JavaScript לפני שתמשיכו במודול זה. לשם כך, וודאו כי הנכם בקיאי במודול צעדים ראשונים ב-JavaScript ובמודול אבני הבניין של JavaScript לפני שתמשיכו במודול זה.

+ +
+

הערה: אם אתם עובדים על מחשב\טבלט\מכשיר אחר שאין לכם אפשרות ליצור עליו קבצים אישיים, אתם יכולים לנסות את (רוב) דוגמאות הקוד על תוכנות קוד אינטרנטיות כמו JSBin או Thimble.

+
+ +

Guides

+ +
+
אובייקטים - עקרונות יסוד
+
במאמר הראשון אנחנו נסתכל על אובייקטים ב-JavaScript, ועל הסינטקס הבסיסי והחשוב של אובייקט. נבקר שוב כמה מאפשרויות של JavaScript שכבר ראינו לפני כן בקורס, ונבין שהרבה מאותן אפשרויות אלו שנתקלנו בהן בעבר, הן בעצם אובייקטים.
+
תכנות מונחה עצמים ב-JavaScript למתחילים
+
לאחר שסיימנו עם הבסיס, נתמקד במעבר על התיאוריה של תכנות מונחה עצמים (object-oriented programming (OOP)) ב-JavaScript (object-oriented JavaScript (OOJS)) - מאמר זה יספק רקע בסיסי על תכנות מונחה עצמים בכלל, ולאחר מכן נחקור כיצד JavaScript מחקה (מלשון: חיקוי) מחלקות (classes) באמצעות constructor functions ואיך אנחנו יוצרים אובייקט.
+
Object prototypes - טיפוסי אב של אובייקט
+
טיפוסי אב - Prototypes - זה המנגנון שבאמצעותו אובייקטים ב-JavaScript יורשים מאפיינים אחד מהשנים, והם עובדים בצורה אחרת מאשר מנגנוני הורשה הקיימים בשפות לתכנות מונחה עצמים אחרות. במאמר זה אנחנו נחקור את ההבדלים השונים, נסביר כיצד שרשרת אבי הטיפוס (prototype chains) עובדת ונסתכל על איך ה-property שנקרא prototype יכול לשמש על מנת להוסיף מתודות לקונסטרקטורים קיימים.
+
הורשה ב-JavaScript
+
לאחר שסיימנו להסביר על התיאוריה של תכנות מונחה עצמים (object-oriented programming (OOP)) ב-JavaScript, מאמר זה יראה איך ליצור מחלקות בנות (constructors) שיורשות מאפיינים מהמחלקות ״הורים״ With most of the gory details of OOJS now explained, this article shows how to create "child" object classes (constructors) that inherit features from their "parent" classes. In addition, we present some advice on when and where you might use OOJS.
+
Working with JSON data
+
JavaScript Object Notation (JSON) is a standard text-based format for representing structured data based on JavaScript object syntax, which is commonly used for representing and transmitting data on web sites (i.e. sending some data from the server to the client, so it can be displayed on a web page). You'll come across it quite often, so in this article we give you all you need to work with JSON using JavaScript, including parsing the JSON so you can access data items within it and writing your own JSON.
+
Object building practice
+
In previous articles we looked at all the essential JavaScript object theory and syntax details, giving you a solid base to start from. In this article we dive into a practical exercise, giving you some more practice in building custom JavaScript objects, which produce something fun and colorful — some colored bouncing balls.
+
+ +

Assessments

+ +
+
Adding features to our bouncing balls demo
+
In this assessment, you are expected to use the bouncing balls demo from the previous article as a starting point, and add some new and interesting features to it.
+
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 +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}
+ +

לאחר שסיימנו עם התיאוריה והפרטים של OOJS, המאמר הזה נועד להראות כיצד ליצור מחלקות אובייקטים ״ילדים״ (constructors) אשר יורשים מההורים שלהם. אנו גם נציג מעין עצות מתי נרצה להשתמש ב-OOJS ונסתכל כיצד ״מחלקות״ מתבצעות בסינטקס המודרני של ECMAScript.

+ + + + + + + + + + + + +
ידע מוקדם: +

אוריינות מחשב בסיסית, הבנה בסיסית ב-HTML ו ב-CSS, היכרות עם יסודות ה-JavaScript (ראה First steps and Building blocks) and OOJS basics (see Introduction to objects).

+
מטרה:להבין כיצד זה אפשרי להחיל הורשה ב- JavaScript
+ +

Prototypal inheritance

+ +

עד עכשיו ראינו קצת הורשה בפעולה - ראינו כיצד prototype chains עובדות וכיצד מתודות ופרופ׳ מורשים בהמשך השרשרת. אבל זה היה בעיקר עם פונקציות מובנות של הדפדפן. כיצד אנחנו יכולים ליצור אובייקט ב-JavaScript אשר יורש מאובייקט אחר?

+ +

דוגמא:

+ +

ראשית, עשו עותק מקומי של הקובץ או ראו אותו כדף אינטרנט. בקוד זה אתם תראו את ה-Person() constructor שהשתמשנו בו לאורך המודול, עם שינוי קל - הגדרנו רק את ה-properties בתוך ה-constructor.

+ +
function Person(first, last, age, gender, interests) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+};
+ +

כל המתודות כולן מוגדרות בתוך ה-constructor's prototype. לדוגמא:

+ +
Person.prototype.greeting = function() {
+  alert('Hi! I\'m ' + this.name.first + '.');
+};
+ +
+

לתשומת לבך: בקוד המקור אתם גם תראו מתודות נוספות שמוגדרות, ()bio ו-()farewell. אנחנו נראה בהמשך כיצד מתודות אלו יכולות להיות מורשות ל-constructors אחרים.

+
+ +

נניח ואנחנו רוצים ליצור מחלקה של Teacher, כמו זו שהסברנו בתחילת המודול לגבי תכנות מונחה עצמים, ומחלקה זו יורשת את כל הפרופ׳ והמתודות של Person, אבל גם כוללת:

+ +
    +
  1. ה- property החדש בשם subject — אשר יכיל את נושאי הלימוד שהמורה מלמד.
  2. +
  3. מתודה ()greeting מעודכנת, אשר תהיה יותר רשמית מהמתודה ()greeting הרגילה.
  4. +
+ +

הגדרה של ה-constructor function בשם ()Teacher

+ +

הדבר הראשון שאנחנו צריכים לעשות הוא להגדיר את ה-constructor בשם ()Teacher - הוסיפו את הקוד הבא מתחת לקוד הנוכחי:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  Person.call(this, first, last, age, gender, interests);
+
+  this.subject = subject;
+}
+ +

זה נראה מאוד דומה ל-constructor בשם Person, אבל משהו פה שונה, משהו שלא ראינו עד כה - פונקציה בשם ()call.

+ +

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

+ +

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

+ +

אנחנו רוצים שה-Teacher() constructor יקבל את אותם פרמטרים כמו שה-Person() constructor שהוא יורש ממנו מקבל, ולכן אנחנו מציינים אותם כפרמטרים בתוך ההפעלה של ה-()call.

+ +

השורה האחרונה בתוך ה-constructor פשוט מגדירה property בשם subject אשר ייחודי למורים, שאנשים רגילים מ-()Person לא מקבלים.

+ +

יכלנו גם לרשום זאת כך, ללא שימוש ב-()call:

+ +
function Teacher(first, last, age, gender, interests, subject) {
+  this.name = {
+    first,
+    last
+  };
+  this.age = age;
+  this.gender = gender;
+  this.interests = interests;
+  this.subject = subject;
+}
+ +

אבל בקוד למעלה זו הגדרה מחדש של ה-properties כחדשים, לא כאלו שיורשים מ- ()Person, אז זה סותר את מה שאנחנו מנסים לעשות - זה לא מוריש אלא זה יוצר חדשים. מה גם שזה לוקח יותר שורות קוד.

+ +

ירושה מ-constructor שלא מקבל פרמטרים

+ +

שימו לב שאם ה-constructor שאנחנו יורשים ממנו לא מקבל את הערכים של ה-property שלו מקבלים מפרמטרים, אז אנחנו לא צריכים לציין אותם כפרמטרים בתוך ה-()call. לדומא, אם היה לנו משהו פשוט כמו זה: :

+ +
function Brick() {
+  this.width = 10;
+  this.height = 20;
+}
+ +

אנחנו יכולים לרשת את ה-properties של ה-width ואת ה-height, באמצעות שימוש בקוד הרשום מטה:

+ +
function BlueGlassBrick() {
+  Brick.call(this);
+
+  this.opacity = 0.5;
+  this.color = 'blue';
+}
+ +

שימו לב שאנחנו רק צריכים לציין את ה-this בתוך ה-()call, ללא פרמטרים נוספים, שכן אנחנו לא יכולים יורשים שום דבר מ-()Brick שהוא קיבל דרך פרמטרים.

+ +

קביעת ה-prototype וה-constructor של ()Teacher

+ +

עד עכשיו הכל עובד תקין, אך יש לנו בעיה. הגדרנו אמנם constructor חדש, ויש לו את ה-property בשם prototype, אשר כברירת מחדל מכיל רק הפנייה ל-constructor function עצמה.

+ +

הוא לא מכיל שום מתודות של ה-property בשם prototype של ה-Person constructor. על מנת לראות זאת, הכניסו (Object.getOwnPropertyNames(Teacher.prototype לתוך הקונסולה.

+ +

לאחר מכן הכניסו זאת שוב, והחליפו את המילה Teacher במילה Person. ה-constructor החדש לא יורש את אותן מתודות. על מנת לראות זאת, השוו את הפלט של Person.prototype.greeting והפלט של Teacher.prototype.greeting. אנחנו צריכים לגרום ל-()Teacher לירוש מתודות שמוגדרות ב-prototype של ()Person. איך עושים זאת?

+ +
    +
  1. הוסיפו את הקוד הבא מתחת לקוד שהוספתם לפני כן: +
    Teacher.prototype = Object.create(Person.prototype);
    + כאן ()create מגיע שוב לעזרה. במקרה הזה, אנחנו משתמשים בו על מנת ליצור אובייקט חדש שיהיה הערך של Teacher.prototype. האובייקט החדש הוא בעל Person.prototype כאובייקט ה-prototype שלו, ולכן, הוא יירש ממנו אם וכאשר יצטרך, את כל המתודות שזמינות ב-Person.prototype.
  2. +
  3. אנחנו צריכים לעשות משהו נוסף לפני שנמשיך הלאה. לאחר שהוספנו את השורה הקודמת, ה-property בשם constructor שווה כעת ל- ()Person, מכיוון שאנחנו הרגע הגדרנו את Teacher.prototype אליו. נסו לשמור את הקוד ולהעלות את הדף בדפדפן וראו זאת על ידי הקלדת Teacher.prototype.constructor בקונסולה.
  4. +
  5. זה יכול להיות בעיה, ולכן אנחנו צריכים לתקן זאת. ניתן לעשות זאת באמצעות הקלדת הקוד הבא מתחת לקוד הנוכחי שלנו.: +
    Object.defineProperty(Teacher.prototype, 'constructor', {
    +    value: Teacher,
    +    enumerable: false, // so that it does not appear in 'for in' loop
    +    writable: true });
    +
  6. +
  7. כעת, אם תשמרו ותרעננו את הדף, הקלדת Teacher.prototype.constructor לקונסולה אמורה להחזיר לכם ()Teacher, כפי שרצינו, ובנוסף אנחנו יורשים מ-()Person.
  8. +
+ +

הענקה ל- Teacher() פונקציית/מתודת greeting() חדשה

+ +

אנו רוצים להגדיר פונקציית ()greeting חדשה בתוך ה-Teacher() constructor שלנו.

+ +

הדרך הפשוטה ביותר לעשות זאת היא להגדיר זאת בתוך ה-prototype של ()Teacher - הוסיפו את הקוד הבא מתחת לקוד הנוכחי:

+ +
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 + '.');
+};
+ +

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

+ +

נסו את הדוגמא הבאה:

+ +

כעת שהכנסו את כל הקוד, נסו ליצור אובייקטים חדשים מ-()Teacher באמצעות הכנסת הקוד הבא מתחת לקוד הנוכחי:

+ +
var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');
+ +

כעת, שמרו את הדף ורעננו ונסו לגשת לפרופ׳ והמתודות של האובייקט teacher1 החדש שלנו. לדוגמא:

+ +
teacher1.name.first;
+teacher1.interests[0];
+teacher1.bio();
+teacher1.subject;
+teacher1.greeting();
+teacher1.farewell();
+ +

הכל אמור לעבוד כשורה. השורות 1,2,3 ו-6 משתמשות במתודות/פרופ׳ שנורשו מה-Person() constructor שלנו. השורה 4 משתמשת בפרופ׳ שזמין רק באמצעות ה-Teacher() constructor שלנו. שורה 5 הייתה יכולה להיות מורשת מ-()Person, אבל מכיוון של-()Teacher יש את אותה מתודה, אז היא ניגשת למתודה שנמצאת ב-()Teacher.

+ +
+

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

+
+ +

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

+ +

אולי תהיו מעוניינים לבדוק חלק מהאפשרויות החדשות ש-{{glossary("ECMAScript")}} מאפשרת לנו, בצורה ״נקייה״ יותר, באמצעות Classes. אנו נגע בדרך זו בהמשך. שימו לב כי דרך חדשה זו לא תומכת בכל הדפדפנים. כל יתר הדרכים שראינו תומכות בדפדנים ישנים גם כמו IE9 ומוקדם יותר ויש דרכים גם לאפשר תמיכה לדפדפנים ישנים יותר.

+ +

דרך מקובלת היא להשתמש בספריית JavaScript - לפופולריות שביניהן יש סט של פונקציונליות שזמין עבור ביצוע הורשה בצורה פשוטה ומהירה. אחת מהן היא CoffeeScript אשר מאפשרת class ,extends לדוגמא.

+ +

המשך תרגול

+ +

במאמר שלנו בנושא OOP theory section, כללנו גם מחלקת Student באופן עקרוני, אשר יורשת תכונות מ-Person וגם יש לה מתודת ()greeting שונה מזו של Person ומשל Teacher. נסתכל כיצד ה-greeting של התלמידים אמורה להיות וננסה לבנות constructor בשם ()Student משלנו, אשר יורש את כל התכונות מ-()Person ומחיל מתודת ()greeting שונה.

+ +
+

שימו לב: אם אתם נתקלים בבעיות, ראו את הגרסה הסופית או כדף אינטרנט .

+
+ +

סיכום בנושא תכונות האובייקט

+ +

על מנת לסכם, יש לנו בעיקרון שלוש סוגים של property/method לדאוג להם:

+ +
    +
  1. אלו המוגדרים בתוך ה-constructor function וניתנים לאובייקטים שנוצרים באמצעות ה- this. אלו בעיקרון מאוד קלים לאיתור - בתוך הקוד שלנו, אלו התכונות שמוגדרות בתוך ה-constructor באמצעות this.x = x, והם זמינים רק עבור האובייקטים שנוצרים (בדרך כלל נוצרים באמצעות ה-constructor ושימוש במילה השמורה new, לדוגמא: ()var myInstance = new myConstructor.
  2. +
  3. אלו המוגדרים ישרות על ה-constructor עצמם, ואלו זמינות רק על ה-constructor. הם לרוב יהיו זמינים רק אובייקטים מובנים של הדפדפן, ואנחנו יכולים לזהות שהם קשורים באופן ישירות ל-constructor ולא למופע אובייקט. לדוגמא ()Object.keys.
  4. +
  5. ואלו המוגדרים על הפרופ׳ בשם prototype של ה-constructor, אשר נורשים על ידי כל מופעי האובייקט שנוצרים או אובייקטים שיורשים מהם. זה כולל כל תכונה שמוגדרת ב-property בשם prototype של ה-Constructor. לדוגמא: ()myConstructor.prototype.x.
  6. +
+ +

אם אתם לא בטוחים מה זה מה, אל תדאגו, אתם תכירו אותם יותר לעומק במהלך הדרך והמשך הקריירה שלכם ככל שתתמודדו איתם.

+ +

ECMAScript 2015 Classes

+ +

ECMAScript 2015 הציגה מעין סינטקס חדש בשם class syntax ל- JavaScript כדרך חדשה לרשום מחלקות לשימוש חוזר, באמצעות סינטקס פשוט ונקי יותר, אשר דומה יותר ל-classes ב-C++ או ב-Java. בחלק הזה של המאמר אנחנו נמיר את הדוגמאות מלמעלה מ-prototypal inheritance ל-classes, על מנת להראות לכם איך לעשות שימוש-classes.

+ +
+

לתשומת לב: דרך חדשה זו של כתיבת classes נתמכת בכל הדפדפנים המודרניים, אבל זה עדיין חשוב להבין את ה-prototypal inheritance במקרה ותיתקלו בפרוייקט שדורש תמיכה בדפדפן שאינו תומך בסינטקס של classes - הידוע מבין כולם הוא Internet Explorer.

+
+ +

נסתכל על הדוגמא שלנו של Person כתובה בצורת classes:

+ +
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!`);
+  };
+}
+
+ +

ההצהרה באמצעות המילה השמורה class מצהירה בעצם בשאנחנו רוצים ליצור class חדשה. בתוך הבלוק הזה שבין {}, אנחנו מגדירים את התכונות של אותה מחלקה:

+ + + +

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

+ +
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
+
+ +
+

לתשומת לב: מאחורי הקלעים, ה-classes שלנו מומרים ל-prototypal Inheritance models - זהו רק syntactic sugar - שזה אומר דרך אחרת מבחינת סינטקס לעשות דבר זהה, אך לא משהו אחר. יחד עם זאת, אין ספק שזו דרך פשוטה יותר להעניק הורשה.

+
+ +

הורשה עם class syntax

+ +

למעלה יצרנו class על מנת לתאר person. יש לנו סט של תכונות שזהות לכל האנשים. בחלק זה אנחנו ניצור את ה-class המיוחד של Teacher, ונגרום לו לירוש מ-Person באמצעות שימוש בסינטקס class החדש. זה נקרא יצירת subclass או ביצוע subclassing.

+ +

על מנת ליצור subclass אנחנו יכולים להשתמש במילה השמורה extends על מנת להגיד ל-JavaScript איזו class אנחנו מתבססים עליה ביצירת ה-class החדשה:

+ +
class Teacher extends Person {
+  constructor(subject, grade) {
+    this.subject = subject;
+    this.grade = grade;
+  }
+}
+ +

אך יש קאצ׳ קטן:

+ +

שלא כמו ה-Constructor function, שבהן האופרטור new operator היה עושה את האתחול של המילה this לאובייקט חדש, פה זה לא קורה בצורה אוטומטית בעבור המחלקה שמוגדרת באמצעות המילה extends, כלומר עבור ה-sub-classes.

+ +

ולכן הרצה שלהקוד למעלה יציג לנו שגיאה:

+ +
Uncaught ReferenceError: Must call super constructor in derived class before
+accessing 'this' or returning from derived constructor
+ +

למחלקות משנה, sub-classes, ההגדרה של this בעבור אובייקט חדש, תהיה תמיד תלויה ב-parent class constructor, כלומר ב-constructor function של ה-class שממנה אנחנו מתרחבים (extending).

+ +

כאן, אנחנו מרחיבים את המחלקה Person- המחלקת משנה בשם -Teacher היא בעצם extension - הרחבה - של המחלקה Person. אז עבור Teacher האתחול של this מתבצע על ידי ה-constructor Person.

+ +

על מנת לקרוא ל-constructor ה-parent, אנחנו צריכים להשתמשש באופרטור ()super , כך:

+ +
class Teacher extends Person {
+  constructor(subject, grade) {
+    super();              // Now `this` is initialized by calling the parent constructor.
+    this.subject = subject;
+    this.grade = grade;
+  }
+}
+ +

אין שום סיבה שתהיה לנו sub-class אם היא לא יורשת מאפיינים מה-parent class.
+ זה רעיון טוב אז שהאופרטור ()super  גם מקבל ארגומנטים בעבור ה- parent constructor.

+ +

כאשר אנחנו מסתכלים על ה- Person constructor,  אנחנו יכולים לראות שיש לו את הבלוק קוד הבא בתוך ה-constructor שלו:

+ +
 constructor(first, last, age, gender, interests) {
+   this.name = {
+     first,
+     last
+   };
+   this.age = age;
+   this.gender = gender;
+   this.interests = interests;
+} 
+ +

מאחר והאופרטור ()super הוא בעצם ה-parent class constructor, העברה של הארגומנטים הרלוונטיים של המחלקת אם, גם תאתחל את הפרופ׳ במחלקת משנה שלנו, ותירש אותם: 

+ +
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;
+  }
+}
+
+ +

כעת, כשיוצרים מופעי אובייקט של Teacher, אנחנו יכולים לקרוא למתודות ופרופ׳ שהוגדרו גם ב-Teacher וגם ב-Person:

+ +
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
+
+ +
+

לתשומת לב: אתם יכולים למצוא את הדוגמא ב-GitHub ב- es2015-class-inheritance.html  או כ-דף אינטרנט.

+
+ +

Getters ו- Setters

+ +

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

+ +

במקרים כאלו אנחנו נוכל להשתמש ב-getters ו-setters.

+ +

נשפר את Teacher class עם  getters ו-setters. המחלקה מתחילה בדיוק כמו שראינו אותה בדוגמא האחרונה.

+ +

 getters ו-setters עובדים בזוגות. getter מחזיר את הערך הנוכחי של משתנה וה-setter הבן זוג שלו משנה את הערך של המשתנה למה שה-setter יגדיר. 

+ +

המחלקה Teacher החדשה תיראה כך:

+ +
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;
+  }
+}
+
+ +

במחלקה למעלה יש לנו getter ו-setter בעבור הפרופ׳ subject. אנחנו משתמשים בסימן _ על מנת ליצור ערך נפרד שבו נאחסכן את השם של הפרופ׳. אם לא נעשה זאת בצורה הזה, אנחנו נקבל שגיאות בכל פעם שנקרא ל-get או ל-set. בנקודה זו: 

+ + + +

הדוגמא למטה מראה את השימוש באפשרויות האלו: 

+ +
// 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"
+
+ +
+

לתשומת לב : תוכלו למצוא את es2015-getters-setters.html ב-GitHub, או כדף אינטרנט.

+
+ +

מתי אנחנו נשתמש בהורשה ב-JavaScript?

+ +

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

+ +

בדרך מסויימת, אנחנו משתמשים בהורשה כל הזמן. בכל פעם שאנחנו משתמשים במאפיינים שונים של Web API או בפרופ׳/מתודות שהוגדרו באובייקט מובנה של הדפדפן (built-in browser object) על מחרוזות, מערכים וכד׳ אנחנו באופן עקיף משתמשים בירושה. 

+ +

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

+ +
+

לתשומת לב: לאור הדרך שבה JavaScript עובדת עם שרשרת אבי הטיפוס (prototype chain) וכד׳ - השיתוף של פונקציונליות בין אובייקטים נקרא לרוב delegation - ״האצלה״. אובייקטים מיוחדים ״מאצילים״ פונקציונליות לאובייקטים שנוצרים.  

+
+ +

כאשר אנחנו משתמשים בהורשה, ההמלצה היא שלא יהיו יותר מדי רמות של הורשה, ושתמיד נעקוב איפה אנחנו מגדירים את המתודות והפרופ׳. זה אפשרי להתחיל לכתוב קוד שבאופן זמני משנה את ה-prototypes של האובייקטים המובנים של הדפדפן (built-in browser objects), אבל אין לעשות זאת אלא אם כן יש לנו סיבה מאוד טובה. יותר מדי הורשה יכולה להוביל לבלבול אינסופי ולשגיאות בקוד. 

+ +

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

+ +

אלטרנטיבות להרחבה של שרשרת ההורשה 

+ +

ב-JavaScript, יש מספר דרכים שונות להרחבה של ה-prototype של אובייקט חוץ מאלו שראינו במאמר זה. להרחבה בנושא, ראו את הדף שלנו בנושא Inheritance and the prototype chain.

+ +

לסיכום

+ +

מאמר זה נועד לסקור את יתרת הנושא של OOJS וסינטקס נוסף שאנחנו חושבים שאתם צריכים לדעת. בנקודה זו אתם אמורים להבין את ההיבטים של אובייקטים ב-JavaScript ואת הבסיס של תכנות מונחה עצמים (OOP), אביט טיפוס, שרשרת אבי-טיפוס, הורשה באמצעות אבי-טיפוס, כיצד ליצור מחלקות (classes), מופעי אובייקטים, הוספת מאפיינים למחלקות, יצירת מחלקות משנה שיורשות ממחלקות אחרות ועוד. 

+ +

במאמר הבא אנחנו נגע כיצד לעבוד עם (JavaScript Object Notation (JSON, פורמט מקובל להעברת מידע.

+ +

ראו גם

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

+ +

במודול זה

+ + diff --git a/files/he/learn/javascript/objects/json/index.html b/files/he/learn/javascript/objects/json/index.html new file mode 100644 index 0000000000..5f61b5aa22 --- /dev/null +++ b/files/he/learn/javascript/objects/json/index.html @@ -0,0 +1,346 @@ +--- +title: Working with JSON +slug: Learn/JavaScript/Objects/JSON +translation_of: Learn/JavaScript/Objects/JSON +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}
+ +

JavaScript Object Notation (JSON) הוא סטדנרט לפורמט מבוסס-טקסט, המבוסס על הסינטקס של אובייקט ב-ה. הוא לרוב משמש בעבור העברת מידע ביישומי רשת (כלומר העברת מידע משרת לקוח, כך שהמידע יוכל להיות מוצג על גבי דף אינטרנט, או ההפך). אנחנו ניתקל בו לעיתים קרובות מאוד ומאמר זה נועד להעניק לכם כל מה שצריך לדעת על עבודה עם JSON כשאנחנו משתמשים ב-JavaScript, כולל עיבוד שלו כך שאנחנו נוכל לגשת למידע המאוחסן בו וכן ליצור JSON.

+ + + + + + + + + + + + +
ידע מוקדם:Basic computer literacy, a basic understanding of HTML and CSS, familiarity with JavaScript basics (see First steps and Building blocks) and OOJS basics (see Introduction to objects).
מטרה:להבין כיצד לעבוד עם מידע המאוחסן בתוך JSON וכיצד ליצור אובייקטי JSON בעצמנו.
+ +

מה זה JSON?

+ +

{{glossary("JSON")}} הוא פורמט מידע מבוסס-טקסט אשר דומה לסינטקס של אובייקט ב-JavaScript. פורמט זה הוצג על ידי Douglas Crockford. למרות שהוא מאוד דומה ומזכיר סינטקס של object literal ב-JavaScript, ניתן להשתמש בו באופן עצמאי ולא רק ב-JavaScript, וסביבות פיתוח אחרות מכילות אפשרויות לקרוא או לעבד וכן ליצור JSON. 

+ +

JSON מתקיים כמחרוזת - שימושי מאוד כשאנחנו רוצים להעביר מידע ברשת. הוא צריך להיות מומר לאובייקט JavaScript כאשר אנחנו רוצים לגשת לאותו מידע שמאוחסן בתוך ה-JSON. זה לא מורכב או מסובך - JavaScript מעניקה לנו את האובייקט JSON הגלובלי שיש לו מתודות שזמינות עבורו בעבור המרה בין JSON למחרוזת.

+ +
+

לתשומת לב: המרה של מחרוזת לאובייקט נקראת parsing ואילו המרה של אובייקט למחרזות כך שהוא יוכל להיות מועבר ברשת, נקראת stringification.

+
+ +

אובייקט JSON יכול להיות מאוחסן בתוך קובץ נפרד משלו, שהוא בעצם קובץ טקסט עם סיימות של .json ו-{{glossary("MIME type")}} של application/json.

+ +

המבנה של JSON

+ +

כפי שציינו למעלה, JSON הוא מחרוזת, שהמבנה שלה מזכיר מאוד object literal ב-JavaScript. אנחנו יכולים לכלול את אותם סוגי מידע בסיסיים בתוך JSON כפי אנחנו יכולים לכלול אותם בתוך אובייקט של JavaScript - מחרוזות, מספרים, מערכים, בוליאנים ואובייקטים אחרים. זה מאפשר לנו ליצור היררכיית מידע כמו זו לדוגמא:

+ +
{
+  "squadName": "Super hero squad",
+  "homeTown": "Metro City",
+  "formed": 2016,
+  "secretBase": "Super tower",
+  "active": true,
+  "members": [
+    {
+      "name": "Molecule Man",
+      "age": 29,
+      "secretIdentity": "Dan Jukes",
+      "powers": [
+        "Radiation resistance",
+        "Turning tiny",
+        "Radiation blast"
+      ]
+    },
+    {
+      "name": "Madame Uppercut",
+      "age": 39,
+      "secretIdentity": "Jane Wilson",
+      "powers": [
+        "Million tonne punch",
+        "Damage resistance",
+        "Superhuman reflexes"
+      ]
+    },
+    {
+      "name": "Eternal Flame",
+      "age": 1000000,
+      "secretIdentity": "Unknown",
+      "powers": [
+        "Immortality",
+        "Heat Immunity",
+        "Inferno",
+        "Teleportation",
+        "Interdimensional travel"
+      ]
+    }
+  ]
+}
+ +

אם אנחנו נטען את האובייקט הזה לתוך תוכנית JavaScript ונמיר אותו (parse) בתוך משתנה בשם superHeroes לדוגמא, אנחנו אז נוכל לגשת לאותו מידע המאוחסן בו באמצעות שימוש ב-00000 שאנחנו מכירים מהמאמר בנושא אובייקטים - עקרונות יסוד. לדוגמא: 

+ +
superHeroes.homeTown
+superHeroes['active']
+ +

על מנת לגשת למידע בהמשך ההיררכיה, אנחנו פשוט נצטרך ״לקשור״ את שם הפרופ׳ המבוקש והאינדקס הרלוונטי במערך ביחד. לדוגמא, על מנת לגשת ל-9999 השלישי של ה-0000 השני ברשימת ה-9999, נוכל לרשום קוד כזה:

+ +
superHeroes['members'][1]['powers'][2]
+ +
    +
  1. ראשית יש לנו את שם המשתנה  — superHeroes.
  2. +
  3. בתוך המשתנה אנחנו רוצים לגשת לפרופ׳ members, אז אנחנו משתמשים ב- ["members"]
  4. +
  5. members מכיל מערך של אובייקטים. אנחנו רוצים לגשת לאובייקט השני בתוך המערך אז אנחנו נשתמש באינדקס [1]
  6. +
  7. בתוך האובייקט, אנחנו רוצים לגשת לפרופ׳ powers, אז אנחנו נשתמש ב-["powers"]
  8. +
  9. ובתוך הפרופ׳ powers, אנחנו נרצה את הערך השלישי, אז אנחנו נשתמש ב-[2]
  10. +
+ +
+

לתשומת לב: יצרנו את ה-JSON שבדוגמא למעלה בקובץ JSONTest.html וניתן לראותו גם ב-קוד המקור

+ +

מנסו להעלות את הקובץ ולגשת למידע בתוך המשתנה באמצעות הקונסולה בדפדפן. 

+
+ +

מערכים כ-JSON

+ +

למעלה ציינו שטקסט ב-JSON דומה בעקרון לאובייקט ב-JavaScript, וזה דיי נכון. הסיבה שאנחנו אומרים ״דומה״ ולא ״זהה״, מכיוון שמערך ב-JavaScript הוא בעצם JSON תקין:

+ +
[
+  {
+    "name": "Molecule Man",
+    "age": 29,
+    "secretIdentity": "Dan Jukes",
+    "powers": [
+      "Radiation resistance",
+      "Turning tiny",
+      "Radiation blast"
+    ]
+  },
+  {
+    "name": "Madame Uppercut",
+    "age": 39,
+    "secretIdentity": "Jane Wilson",
+    "powers": [
+      "Million tonne punch",
+      "Damage resistance",
+      "Superhuman reflexes"
+    ]
+  }
+]
+ +

הטקסט למעלה הוא JSON תקין לחלוטין. אנחנו פשוט נצטרך לגשת לאיברים במערך (בגרסה המעובדת שלו), באמצעות אינדקס של מערך/

+ +

הערות נוספות

+ + + +

למידה עצמאית: עבודה עם JSON

+ +

כעת נלמד באמצעות דוגמא כיצד ניתן לעשות שימוש במידע JSON באתר אינטרנט.

+ +

התחלה

+ +

על מנת להתחיל, עשו עותקים מקודמיים של heroes.html ושל style.css . הקובץ האחרון מכיל CSS פשוט לעיצוב הדף שלנו והראשון מכיל גוף HTML פשוט:

+ +
<header>
+</header>
+
+<section>
+</section>
+ +

בנוסף, הקובץ הראשון מכיל אלמנט {{HTMLElement("script")}} פשוט שיכיל את קוד ה-JavaScript שנכתוב בתרגיל זה. כעת, קובץ זה מכיל שתי שורות, אשר מכילות הפניה לאלמנט {{HTMLElement("header")}} ולאלמנט {{HTMLElement("section")}} ומאחסן הפניות אלו בתוך משתנים:

+ +
var header = document.querySelector('header');
+var section = document.querySelector('section');
+ +

מידע ה-JSON זמין ב-GitHub בכתובת: https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json.

+ +

בתרגיל אנחנו נעלה את המידע לתוך הדף שלנו, באמצעות שימוש במניפולציות על ה-DOM, כך שהדף שלנו ייראה כך:

+ +

+ +

קבלת ה-JSON

+ +

על מנת להשיג את ה-JSON, אנחנו נשתמש ב-API שנקרא {{domxref("XMLHttpRequest")}} (לרוב נקרא XHR). זהו אובייקט JavaScript שימושי מאוד, אשר מאפשר לנו לבצע בקשות רשת על מנת לקבל משאבים מהשרת באמצעות JavaScript (כמו תמונות, טקסט, JSON, ואפילו קוד HTML), כלומר, אנחנו יכולים לעדכן חלקים מתוך התוכן שלנו, מבלי לטעון מחדש את הדף כולו. אפשרות זו איפשה לדפי אינטרנט להיות הרבה יותר רספונסיביים. אנחנו נלמד בהרחבה על נושא זה בהמשך. 

+ +
    +
  1. על מנת להתחיל, אנחנו הולכים לאחסן את ה-URL של ה-JSON שאנחנו נרצה לקבל בתוך משתנה. הוסיפו את הקוד הבא בתחתית הקוד של JavaScript שברשותכם:
  2. +
  3. +
    var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
    +
  4. +
  5. על מנת ליצור בקשה, אנחנו צריכים ליצור אובייקט בקשה חדשה מה-constructor בשם XMLHttpRequest, באמצעות שימוש במילה השמורה new. הוסיפות את הקוד הבא מתחת לשורה האחרונה: +
    var request = new XMLHttpRequest();
    +
  6. +
  7. כעת, אנחנו צריכים לפתוח בקשה חדשה לאובייקט בקשה שיצרנו באמצעות המתודה ()open. הוסיפו את הקוד הבא: +
    request.open('GET', requestURL);
    + +

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

    + +
      +
    • סוג המתודה של HTTP שאנחנו נרצה לבצע בבקשת השרת - במקרה שלנו זו תהיה GET, שכן אנחנו רוצים לקבל מידע כלשהו. 
    • +
    • ה-URL שאנחנו נבצע אליו בקשה - זהו ה-URL שבו מאוחסן קובץ ה-JSON שלנו. 
    • +
    +
  8. +
  9. כעת, הוסיפו את השורות הבאות  - בשורות אלו אנחנו מגדירים את ה-responseType ל-JSON, כך שה-XHR יודע שהשרת יחזיר לנו JSON, ושמאחורי הקלעים תבוצע לו המרה לאובייקט JavaScript. בשורה השנייה אנחנו שולחים את הבקשה באמצעות מתודת ()send: +
    request.responseType = 'json';
    +request.send();
    +
  10. +
  11. החלק האחרון של הקוד הרשום להלן הוא בעצם המתנה לקבלת תגובה מהשרת, וביצוע פעולה איתה. הוסיפו את הקוד הבא מתחת לקוד הנוכחי שלכם: +
    request.onload = function() {
    +  var superHeroes = request.response;
    +  populateHeader(superHeroes);
    +  showHeroes(superHeroes);
    +}
    +
  12. +
+ +

כאן אנחנו מאחסנים את התגובה לבקשה לשלנו (הזמינה בפרופ׳ response ) בתוך משתנה שנקרא superHeroes. המשתנה עכשיו מכיל את האובייקט JavaScript שמבוסס על ה-JSON. לאחר מכן אנחנו מעבירים את אותו אובייקט כארגומנט לשתי קריאות פונקציות - הראשונה תמלא את ה-<header> עם המידע הנכון, ואילו השניה תיצור לנו כרטיס מידע בעבור כל ״גיבור״ בקבוצה ותכניס את הכרטיס הזה לתוך <section>

+ +

עטפנו את הקוד הזה בתוך מטפל אירוע - event handler - שירוץ ברגע שהאירוע load נוצר על האובייקט request (ראו onload) - זה מכיוון שהאירוע load נוצר כאשר התגובה מהשרת הוחזרה בהצלחה. ביצוע של דבר זה מבטיח לנו שה-request.response יהיה זמין בוודאות כשנרצה לעשות משהו איתו.

+ +

מילוי של מידע ב-header

+ +

כעת, כשהשגנו את המידע ב-JSON והמרנו אותו לאובייקט JavaScript, אנחנו יכולים לעשות בו שימוש באמצעות כתיבה של הפונקציות שציינו למעלה. ראשית, הוסיפו את הפונקציות הרשומות מטה מתחת לקוד הנוכחי שלכם: 

+ +
function populateHeader(jsonObj) {
+  var myH1 = document.createElement('h1');
+  myH1.textContent = jsonObj['squadName'];
+  header.appendChild(myH1);
+
+  var myPara = document.createElement('p');
+  myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed'];
+  header.appendChild(myPara);
+}
+ +

אנחנו קראנו לפרמטר בשם jsonObj, על מנת להזכיר לעצמנו שזהו בעצם אובייקט JavaScript שמקורו ב-JSON. ראשית, יצרנו אלמנט {{HTMLElement("h1")}} עם ()createElement, והשמנו את ה-textContent שיהיה שווה לפרופ׳ squadName של האובייקט, ולאחר מכן שייכנו אותו ל-header באמצעות ()appendChild

+ +

לאחר מכן עשינו פעולה דומה בעבור הפסקה - p: יצרנו אותה, השמנו את ה-textContent שלה ולאחר מכן הוספנו אותה ל-header. ההבדל היחיד הוא שהטקסט שלה הוא שרשור של מחרוזות המכילות את הפרופ׳ homeTown ו-formed של האובייקט jsonObj.

+ +

יצירה של כרטיסי המידע ״hero״

+ +

כעת, הוסיפו את הפונקציה הבאה מתחת לקוד הנוכחי, אשריוצרץ ומצגיה את כרטיסי המידע של ה-hero: 

+ +
function showHeroes(jsonObj) {
+  var heroes = jsonObj['members'];
+
+  for (var i = 0; i < heroes.length; i++) {
+    var myArticle = document.createElement('article');
+    var myH2 = document.createElement('h2');
+    var myPara1 = document.createElement('p');
+    var myPara2 = document.createElement('p');
+    var myPara3 = document.createElement('p');
+    var myList = document.createElement('ul');
+
+    myH2.textContent = heroes[i].name;
+    myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity;
+    myPara2.textContent = 'Age: ' + heroes[i].age;
+    myPara3.textContent = 'Superpowers:';
+
+    var superPowers = heroes[i].powers;
+    for (var j = 0; j < superPowers.length; j++) {
+      var listItem = document.createElement('li');
+      listItem.textContent = superPowers[j];
+      myList.appendChild(listItem);
+    }
+
+    myArticle.appendChild(myH2);
+    myArticle.appendChild(myPara1);
+    myArticle.appendChild(myPara2);
+    myArticle.appendChild(myPara3);
+    myArticle.appendChild(myList);
+
+    section.appendChild(myArticle);
+  }
+}
+ +

לשם התחלה, אחסנו את הפרופ׳ members של אובייקט ה-JavaScript בתוך משתנה חדש. מערך זה מכיל מספר אובייקטים שמכילים את המידע בעבור כל hero. 

+ +

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

+ +
    +
  1. יצרנו מספר אלמנטים חדשים: <article><h2>, שלוש <p>, ו-<ul>.
  2. +
  3. קבענו ש- <h2> יכיל את הערך הנוכחי של ה-name של ה-hero.
  4. +
  5. מילאנו את שלושת ה-p עם secretIdentity, age ושורה עם הטקסט "Superpowers:".
  6. +
  7. אחסנו את הפרופ׳ powers בתוך משתנה חדש שנקרא superPowers - זה מכיל מערך שמציג את ה-superpowers הנוכחיים.
  8. +
  9. השתמשנו בלולאת for שוב על מנת לעבור על כל ה-superpowers הנוכחיים של hero - בעבור כל אחד יצרנו אלמנט <li>, והכנסו את ה-superpower לתוכו ולאחר מכן שמנו את ה-listItem בתוך <ul> באמצעות ()appendChild.
  10. +
  11. לבסוף, שייכנו את <h2>, <p> ו-<ul> לתוך <article> (myArticle) ולאחר מכן שייכנו את <article> לתוך <section>. הסדר שבו דברים משוייכים הוא חשוב שכן כך הם יוצגו על גבי הדף.
  12. +
+ +
+

לתשומת לב: אם אתם נתקלים בבבעיה, ראו את הקוד המקור ב-heroes-finished.html או כ-דף אינטרנט

+
+ +
+

לתשומת לב:  אם אתם מתקשים בעניין ה-dot/bracket notation שאנו משתמשים כדי לגשת לאובייקט JavaScript, אולי יעזור לכם לפתוח את הקובץ superheroes.json בלשונית אחרת או בעורך הקוד שלכם, ולהסתכל עליו תוך כדי מעבר על הקוד שלנו. בנוסף, שקלו לעשות חזרה על המאמר שלנו בנושא אובייקטים - עקרונות יסוד.

+
+ +

המרה בין אובייקטים וטקסט

+ +

הדוגמא למעלה הייתה יחסי פשוטה במונחים של לגשת לאובייקט JavaScript, מכיוון שקבענו שבקשת ה-XHR שלנו תמיר את התגובת JSON ישירות לאובייקט JavaScript באמצעות: 

+ +
request.responseType = 'json';
+ +

לפעמים אנחנו נקבל מחרוזת JSON לא מעובדת, ואנחנו נצטרך להמיר אותה לאובייקט בעצמנו. וכאשר אנחנו נרצה לשלוח אובייקט JavaScript ברשת, אנחנו נצטרך להמיר אותו ל-JSON (מחרוזת) לפני השליחה שלו. למזלנו, שתי בעיות אלו כל כך נפוצות, שקיים אובייקט בשם JSON הזמין בכל הדפדפנים, המכיל שתי מתודות: 

+ + + +

אתם יכולים לראות את הראשון בפעולה בקובץ -heroes-finished-json-parse.html - הוא עושה בדיוק את אותו הדבר כמו בדוגמא שבנינו קודם, רק שאנחנו קבענו שה-XHR יחזיר טקסט JSON גולמ, ואז השתמשנו ב-()parse על מנת להמיר אותו לאובייקט JavaScript זה הקוד הרלוונטי:

+ +
request.open('GET', requestURL);
+request.responseType = 'text'; // now we're getting a string!
+request.send();
+
+request.onload = function() {
+  var superHeroesText = request.response; // get the string from the response
+  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
+  populateHeader(superHeroes);
+  showHeroes(superHeroes);
+}
+ +

כפי שאתם יכולים לנחש, ()stringify עובד בדרך ההפוכה. נסו להזין את השורות הבאות לקונסולה:

+ +
var myJSON = { "name": "Chris", "age": "38" };
+myJSON
+var myString = JSON.stringify(myJSON);
+myString
+ +

כאן יצרנו אובייקט JavaScript ואז המרנו אותו למחרוזת JSON באמצעות ()stringify - ושמרנו את הערך שחזר במשתנה חדש. 

+ +

לסיכום

+ +

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

+ +

ראו גם

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}

+ +

In this module

+ + diff --git a/files/he/learn/javascript/objects/object-oriented_js/index.html b/files/he/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..63f83aa94d --- /dev/null +++ b/files/he/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,275 @@ +--- +title: Object-oriented JavaScript for beginners +slug: Learn/JavaScript/Objects/Object-oriented_JS +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}
+ +

לאחר שסיימנו עם עקרונות היסוד, כעת אנחנו נתמקד על- object-oriented JavaScript (OOJS) — מאמר זה נועד להעניק מבט בסיסי של תיאוריית object-oriented programming (OOP) ולאחר מכן נחקור כיצד JavaScript מחקה (מלשון חיקוי) מחלקות אובייקטים באמצעות פנקציה בנאית (constructor functions), וכיצד אנחנו יכולים ליצור ״מופעי״ אובייקטים

+ + + + + + + + + + + + +
ידע מוקדם:Basic computer literacy, a basic understanding of HTML and CSS, familiarity with JavaScript basics (see First steps and Building blocks) and OOJS basics (see Introduction to objects).
מטרה:להבין את בסיס התיאוריה שעומדת מאחורי תכנות מונחה עצמים, וכיצד זה מתקשר ל- JavaScript ("everything is an object"), ולהבין כיצד ליצור constructors ו- object instances.
+ +

Object-oriented programming — הבסיס

+ +

לשם ההצלחה, ננסה ללהעניק לכם נקודת מבט מופשטת, מלמעלה, של מה זה בעצם תכנות מונחה עצמים - Object-oriented programming (OOP). אנחנו אומרים מופשט מכיוון ש-0000 יכול להיות מורכב מאוד ופירוט של כל התיאוריה רוב הסיכויים תבלבל אתכם. הרעיון הבסיסי של OOP הוא שאנחנו משתמשים באובייקטים על מנת לדמות דברים אמיתיים מהעולם האמיתי שנרצה לכלול בתוך התוכנית שלנו, ו/או להעניק דרך פשוטה לגשת לפונקציונליות מסויימת, שבדרכים אחרות היה פשוט בלתי אפשרי או מסובך מאוד.

+ +

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

+ +

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

+ +

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

+ +

על מנת להתחיל, אנחנו נחזור לאובייקט Person מהמאמר הקוד אובייקטים - עקרונות יסוד, אשר מגדיר את המידע והפונקציונליות הגנריות של בן אדם, של person. יש הרבה דברים שאנחנו יכולים לדעת על אדם (כתובת, גובה, מידת נעליים וכד׳), אבל במקרה שלנו אנחנו מעונינים להראות את השם, גיל, מין תחומי עניין שלהם, ואנחנו רוצים שתאפשר לנו לכתוב הקדמה קצרה עליהם, בהתבסס על המידע שיש לנו ולאפשר לאותו אובייקט להגיד שלום בצורה כלשהי. זה בעצם נקרה abstraction — יצירת מודל פשוט של משהו מורכב יותר אשר מייצג את האספקטיים החשובים ביותר בדרך כזו שניתן לעבוד איתה בתוכנית שלנו ולצרכי התוכנית שלנו.

+ +

+ +

יצירת אובייקטים

+ +

מהמחלקה שלנו אנחנו יכולים ליצור מופעי אובייקט - object instances — אלו בעצם אובייקטים המכילים את המידע והפונקציונליות שהוגדרו ב-מחלקה. מהמחלקה Person שלנו, אנחנו יכולים ליצור כמה אנשים בפועל:

+ +

+ +

כאשר נוצר מופע אובייקט ממחלקה, ה- constructor function של אותה מחלקה מורץ על מנת ליצור את האובייקט החדש. תהליך זה של יצירת מופע אובייקט ממחלקה נקרא instantiation — ומופע האובייקט שנוצר, האובייקט שנוצר, אנו אומרים שהוא instantiated מהמחלקה

+ +

Specialist classes

+ +

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

+ +

+ +

זהו מאוד שימושי - מורים וסטודנטים חולקים מאפיינים בסיסיים כמו שם, גיל, מין כך שזה יהיה נוח אם נוכל להגדיר את המאפיינים הללו פעם אחת בלבד. אנחנו גם יכולים להגדיר מאפיינים דומים באופן נפרד, במחלקות שונות, כך שכל מאפיין שכזה יהיה ב-namespace אחר. לדוגמא,הברה של סטודנט יכולה להיות שונה מהברכה של מורה. כך לדוגמא, הברכה של סטודנט תהיה "Yo, I'm [firstName]" (e.g Yo, I'm Sam), בעוד הברכה של מורה תהיה "Hello, my name is [Prefix] [lastName], and I teach [Subject]." (e.g Hello, My name is Mr Griffiths, and I teach Chemistry).

+ +
+

לתשומת לב: המילה הרשמית לאפשרות לשכפל אובייקטים ולהחיל עליהם את אותה פונקציונליות נקראת polymorphism. רק למקרה ותהיתם

+
+ +

אנחנו יכולים ליצור מופעי אובייקטים חדשים מה-child classes. לדוגמא:

+ +

+ +

בהמשך המאמר, אנחנו נסתכל כיצד תיאורית oop באה לידי ביטוי ב-JavaScript.

+ +

Constructors ו- object instances

+ +

JavaScript  משתמש בפונקציות מיוחדות שנקראות constructor functions על מנת להגדיר ול initialize אובייקטים ואת המאפיינים שלהם. זה שימושי מאוד מכיוון שאנחנו ניתקל בסיטואציות שבהן אנחנו לא יודעים כמה אובייקטים אנחנו נרצה או נצטרף ליצור. constructors מאפשרים לנו ליצור אובייקטים כמה שנרצה בדרך אפקטיבית, וך צירוף המידע והפונקציות שלהם ככל שנרצה.

+ +

נחקור כעת יצירה של מחלקות באמצעות constructors ויצירה של מופעי אובייקט מהם ב-JavaScript. ראשית, אנא צרו עותק של oojs.html

+ +

דוגמא פשוטה

+ +
    +
  1. נתחיל בכך שנסתכל כיצד אנחנו יכולים להגדיר person באמצעות פונקציה רגילה. הוסיפו את הפונקציה הזו לתוך אלמנט script : + +
    function createNewPerson(name) {
    +  var obj = {};
    +  obj.name = name;
    +  obj.greeting = function() {
    +    alert('Hi! I\'m ' + obj.name + '.');
    +  };
    +  return obj;
    +}
    +
  2. +
  3. כעת אנחנו יכולים ליצור person חדש באמצעות קריאה לפונקציה זו - נסו להזין אתהקוד הבא בקונסולה: +
    var salva = createNewPerson('Salva');
    +salva.name;
    +salva.greeting();
    + זה עובד בצורה טובה, אבל קצת מפותלת. אם אנחנו יודעים שאנחנו רוצים ליצור אובייקט, מדוע אנחנו צריכים ליצור במפורש אובייקט ריק בהתחלה ולהחזיר אותו? למרבה המזל, javascript מעניקה לנו קיצור שימושי פונקציה בנאית- constructor functions - בואו ניצור אחת יחד:
  4. +
  5. החליפו את הפונקציה הקודמת עם הפונקציה הנוכחית: +
    function Person(name) {
    +  this.name = name;
    +  this.greeting = function() {
    +    alert('Hi! I\'m ' + this.name + '.');
    +  };
    +}
    +
  6. +
+ +

ה-constructor function היא הגרסה של javascript למחלקות. שימו לב שיש לה את כל המאפיינים שאנחנו נצפה לראות בפונקציה, למרות שהיא לא מחזירה שום דבר או יוצרת אובייקט באופן מפורש - היא בסך הכל מגדירה מפתחות ומתודות. אנו משתמשים במילה השמורה this — זה בעיקרון אומר שבכל פעם שנוצר מופע אובייקט, ה- name property יהיה שווה לערך של name value שהועבר לתוך ה- constructor, והמתודה greeting() תשתמש באותם ערכים שהועברו ל- constructor.

+ +
+

שימו לב:שם של constructor function בדרך כלל מתחיל עם אות גדולה - זו מוסכמה מקובלת על מנת לזהות בקלותconstructor functions קוד שלנו.

+
+ +

אז כיצד אנחנו קוראים ל-constructor function על מנת ליצור אובייקטים?

+ +
    +
  1. הוסיפו את השורות הבאות מתחת לקוד הקודם שהוספתם: +
    var person1 = new Person('Bob');
    +var person2 = new Person('Sarah');
    +
  2. +
  3. שמרו ורעננו את הדף ולאחר מכן הזינו את השורות הבאות בקונסולה: +
    person1.name
    +person1.greeting()
    +person2.name
    +person2.greeting()
    +
  4. +
+ +

אתם תראו שאנחנו יצרנו שני אובייקטים חדשים, כאשר כל אחד מהם נשמר תחת שם אחר — כאשר אנחנו רוצים לגשת למפתחות ולמתודות שלהם, אנחנו צריכים להתחיל עם קריאה ל person1 או ל- person2; הפונקציונליות המאוחסנת בהם ארוזה בצורה מסודרת כך שהיא תתנגש עם פונקציונליות אחרת. יחד עם זאת, יש להם את אותו מפתח name  ואת אותה מתודת greeting() שזמינה עבורה. שימו לב שהם משתמשים בערך של ה - name שניתן להם כאשר הם נוצרו. זו אחת מהסיבות מדוע זה מאוד חשוב להתשמש במילה this, כך שהם ישתמשו בערכים שלהם ולא בערכים אחרים.

+ +

נסתכל שוב על הקריאות ל- constructor שוב:

+ +
var person1 = new Person('Bob');
+var person2 = new Person('Sarah');
+ +

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

+ +
function Person(name) {
+  this.name = name;
+  this.greeting = function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  };
+}
+ +

לאחר שהאובייקטים החדשים נוצרו, המשתנים person1 ו- person2 מכילים את האובייקטים הבאים:

+ +
{
+  name: 'Bob',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+
+{
+  name: 'Sarah',
+  greeting: function() {
+    alert('Hi! I\'m ' + this.name + '.');
+  }
+}
+ +

שימו לב שכאשר אנחנו קוראים ל-constructor function שלנו, אנחנו מגדירים את המתודה greeting() בכל פעם - משהו שאינו אידיאלי. על מנת להימנע מכך, אנחנו נגדיר פונקציות שהוא בתבנית האב - אנו נגע בנושא זה בהמשך.

+ +

יצירת ה-constructor הסופי שלנו

+ +

הדוגמא שהסברנו למעלה הייתה דוגמא פשוטה שנועדה רק לסבר לנו את האוזן. כעת, ניצור את ה-constructor function code>Person() הסופי שלנו.

+ +
    +
  1. הסירו את הקוד שהכנסתם עד עכשיו, והוסיפו את ה - constructor הזה - הוא בעצם אותו דבר כמו בדוגמא למעלה, רק קצת יותר מורכב: : +
    function Person(first, last, age, gender, interests) {
    +  this.name = {
    +     first : first,
    +     last : last
    +  };
    +  this.age = age;
    +  this.gender = gender;
    +  this.interests = interests;
    +  this.bio = function() {
    +    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
    +  };
    +  this.greeting = function() {
    +    alert('Hi! I\'m ' + this.name.first + '.');
    +  };
    +}
    +
  2. +
  3. כעת, הוסיפו את הקוד הבא מתחת, על מנת ליצור מופעי אובייקט מ-constructor: +
    var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
    +
  4. +
+ +

אתם תראו שאנחנו יכולים לגשת לכל אחד מהמפתחות והמתודות בדיוק כפי שיכלנו לפני כן - נסו להזין את הקוד הבא בקונסולה:

+ +
person1['age']
+person1.interests[1]
+person1.bio()
+// etc.
+ +
+

לתשומת לב: אם אתם נתקלים בבעיות, נסו להשוות את הקוד שלכם לקוד שלנו - oojs-class-finished.html או ראו את דף האינטרנט.

+
+ +

תרגולים נוספים

+ +

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

+ +

בנוסף, יש מספר בעיות עם המתודה bio() — הפלט שלה תמיד יציג פלט בלשון זכר, למרות ש-person הוא נקבה. והמתמודה גם תציג רק שני תחומי עניין, אפילו אם בתוך המערך interests יש יותר תחומי עניין. האם אתם יכולים לתקן את זה ב-constructor שלנו? אם יכולים לשים כל קוד בתוך הconstructor (אתם כנראה תצרו משפטי תנאי ולולאה). חשבו כיצד המשפטים אמורים להיראות בצורה שונה כאשר מדובר במין שונה ומה עושים כאשר מספר תחומי העניין הוא 1, 2 או יותר מ-2.

+ +
+

לתשומת לב: אם אתם נתקעים, ראו את התשובה ב- GitHub repo או בדף היאנטרנט) — אך נסו בעצמכם לפני כן

+
+ +

דרכים נוספות ליצירת מופעי אובייקט - ליצירת אובייקטים חדשים

+ +

עד עכשיו ראינו שתי דרכים ליצירת מופעי אובייקט — הצהרה על אובייקט ליטראלי, ובאמצעות שימוש ב - constructor function (כפי שראינו למעלה).

+ +

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

+ +

The Object() constructor

+ +

ראשית, אתם יכולים לעשות שימוש ב constructor Object() על מנת ליצור אובייקט חדש. כן, גם אובייקטים גנריים יש להם constructor, אשר יוצר אובייקט ריק.

+ +
    +
  1. נסו להזין את הקוד הבא לתוך הקונסולה: +
    var person1 = new Object();
    +
  2. +
  3. קוד זה מאחסן בעצם אובייקט ריק בתוך המשתנה person1 .אנחנו יכולים להוסיף מפתחות ומתודות לאובייקט זה באמצעות שימוש ב- dot או dot; נסו להזין את הדוגמאות הבאות בקונסולה: +
    person1.name = 'Chris';
    +person1['age'] = 38;
    +person1.greeting = function() {
    +  alert('Hi! I\'m ' + this.name + '.');
    +};
    +
  4. +
  5. אתם גם יכולים להעביר object literal ל- Object() constructor כפרמטר, על מנת למלא מראש את הפרופ׳ והמתודות: נסו להזין את הקוד הבא בקונסולה: +
    var person1 = new Object({
    +  name: 'Chris',
    +  age: 38,
    +  greeting: function() {
    +    alert('Hi! I\'m ' + this.name + '.');
    +  }
    +});
    +
  6. +
+ +

שימוש במתודת create()

+ +

Constructors יכולים לעזור להעניק סדר לקוד שלנו - אנחנו יכולים ליצור את הconstructors במקום אחד ואז ליצור מופעים שלהם כמה שנרצה, במקום אחר, וזה יהיה ברור מאיפה הם נוצרוץ

+ +

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

+ +
    +
  1. העלו את התרגיל שסיימתם בתרגול הקודם לדפדפן והוסיפו את הקוד הבא לקונסולה: : +
    var person2 = Object.create(person1);
    +
  2. +
  3. כעת נסו להזין את הקוד הבא בקונסולה: +
    person2.name
    +person2.greeting()
    +
  4. +
+ +

אתם תראו ש-person2 נוצר בהתבסס על person1 - יש לו את אותם פרופ׳ ומתודות שזמינות עבורו.

+ +

הגבלה אחת שיש בשימוש עם מתודת create() היא שדפדפן IE8 does לא תומך בה. אז constructors יכולים להיות דרך רלוונטם במידה ואתם צריכים לתמוך בגרסה זו.

+ +

אנו נחקור את המתודה create() בפרטי פרטים בהמשך הקורס.

+ +

לסיכום

+ +

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

+ +

במאמר הבא אנחנו נחקור את נושא JavaScript object prototypes.

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}

+ +

במודול זה

+ + diff --git a/files/he/learn/javascript/objects/object_prototypes/index.html b/files/he/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..0afe0ef67d --- /dev/null +++ b/files/he/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,283 @@ +--- +title: Object prototypes +slug: Learn/JavaScript/Objects/Object_prototypes +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}
+ +

Prototypes - אבי טיפוס, זה המנגנון שבאמצעותו אובייקטים של javascript יורשים מאפיינים אחד מהשני. במאמר זה אנחנו נסביר כיצד שרשראות אבי טיפוס - (prototype chains) עובדות ונסתכל כיצד מאפיין (property) בשם prototype יכול לשמש עבור הוספת מתודות ל-constructors קיימים.

+ + + + + + + + + + + + +
ידע מוקדם: +

הבנה של פונקציות ב-JavaScript, הכרות עם הבסיס של JavaScript (ראו את המאמר צעדים ראשונים ב-צעדים ראשונים ב-JavaScript ו-אבני הבניין של JavaScript) וכן הבסיס של תכנות מונחה עצמית ב-JavaScript (ראו אובייקטים - עקרונות יסוד).

+
מטרה:הבנה של JavaScript object prototypes, כיצד שרשראות prototype עובדות, וכיצד להוסיף מתודות חדשות לתוך פרופ׳ בשם prototype .
+ +

שפה מבוססת אב-טיפוס?

+ +

JavaScript לעיתים קרובות מתוארת כשפה מונחית אבי-טיפוס (prototype-based language) - על מנת לאפשר הורשה, לאובייקטים יכול להיות אובייקט אב-טיפוס (prototype object), אשר מתפקד כאובייקט תבנית - אובייקט אב טיפוס אשר ממנו האובייקטים יכולים לירוש מתודות (methods) ומאפיינים (properties).

+ +

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

+ +

ליתר דיוק, המתודות והמאפיינים מוגדרים במאפיין (property) בשם prototype ב-constructor functions ולא באובייקטים עצמם שנוצרו (object instance).

+ +

ב-JavaScript, נוצר קשר בין האובייקט שנוצר (object instance) לבין אב הטיפוס/prototype שלו באמצעות ״הליכה״ על שרשרת אבי הטיפוס. אנו נוכל לראות את אב הטיפוס של אובייקט ב-property של האובייקט שנוצר בשם __proto__ . שם זה נגזר מ-prototype שמוגדר בכלל ב-constructor.  

+ +
+

לתשומת לב:  חשוב להבין שיש אבחנה בין אב הטיפוס של האובייקט  (object' s prototype) אשר זמין באמצעות (Object.getPrototypeOf(obj או באמצעות מאפיין __proto__לבין מאפיין (property) בשם אב-טיפוס (prototype) אשר נמצא ב-constructor functions. 

+ +

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

+
+ +

נסתכל על דוגמא על מנת להבין זאת לעומק.

+ +

הבנה של אובייקטים מסוג אב-טיפוס

+ +

נחזור לדוגמא הקודמת שבה סיימנו לכתוב את ה-constructor שלנו ()Person:

+ +

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

+ +

בדוגמא זו, אנחנו מגדירים את ה -constructor function שלנו כך:

+ +
function Person(first, last, age, gender, interests) {
+
+  // property and method definitions
+  this.first = first;
+  this.last = last;
+//...
+}
+ +

אנו יוצרים אובייקטים מה-constructor function שהגדרנו כך:

+ +
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
+ +

אם תקלידו .person1 בקונסולה, אתם אמורים לראות שהדפדפן מנסה להשלים באופן אוטומטי אפשרויות הזמינות עבור אובייקט זה: 

+ +

+ +

ברשימה זו, אתם יכולים לראות את הפרופ׳ ומתודות שהוגדרו ב-constructor Person()name, age, gender, interests, bio, ו- greeting. בנוסף, אנחנו גם נראה פרופ׳ ומתודות נוספות - watch, valueOf וכד׳ - אלו מוגדרים בתבנית אב הטיפוס (prototype object) של ()Person, שזה  Object.

+ +

+ +

מה קורה כשאנחנו רוצים לקרוא למתודה, להפעיל מתודה על person1, אשר מוגדרת ב-Object?:

+ +
person1.valueOf()
+ +

המתודה הזו - ()Object.valueOf נורשת על ידי person1 בגלל שתבנית אב הטיפוס של האובייקט (הפונקציה ()Person) שיצר אותו היא  ()Object. המתודה ()valueOf מחזירה את הערך של האובייקט שהיא נקראה עליו: 

+ + + +
+

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

+
+ +
+

לתשומת לב: אין דרך רשמית להיכנס לאובייקט אב הטיפוס של אובייקט בצורה ישירה  הקשרים שבין הפריטים בשרשרת מוגדר בתוך פרופ׳ פנימי - שנקרא [[prototype]] במסמכים של השפה - ראו גם {{glossary("ECMAScript")}}. 

+ +

מרבית הדפדפנים המודרניים מכילים פרופ׳ שזמין שנקרא בשם __proto__, אשר מכיל את האובייקט שהוא תבנית האב של האובייקט הרלוונטי. לדוגמא, נסו להזין person1.__proto__ ו- person1.__proto__.__proto__ לראות איך זה נראה. החל מ-ECMAScript 2015 אנחנו יכולים לגשת לאובייקט אב הטיפוס של אובייקט באמצעות Object.getPrototypeOf(obj).

+
+ +

The prototype property: היכן שמגדירים מה מורישים

+ +

אז, היכן הפרופ׳ והמתודות שמורישים מוגדרים? אם אנחנו מסתכלים על הדף Object, אנחנו נראה רשימה מצד של שמאל של פרופ׳ ומתודות - הרבה יותר מאלו שראינו שזמינות עבור person1. למה? מכיוון שחלקם הורשו ל-person1 וחלקם לא. 

+ +

כפי שהוסבר למעלה, אלו שנורשו הם אלו שמוגדרים במאפיין (property) בשם prototype - כלומר אלו הם שמתחילים עם .Object.prototype ולא אלו שרק מתחילים עם Object. הערך של המאפיין prototype הוא אובייקט, אשר בעצם הוא מאחסן את כל הפרופ׳ והמתודות שאנחנו רוצים להוריש לאובייקטים בהמשך ה-prototype chain.

+ +

כך לדוגמא, ()Object.prototype.watch ו- ()Object.prototype.valueOf זמינות עבור כל אובייקט שיירש מ-Object.prototype, כולל מופעים חדשים של אובייקטים מה-()constructor Person

+ +

לעומת זאת, ()Object.is ו-()Object.keys לדוגמא, לא מוגדרים בתוך () ולכן לא נוריש אותם לאובייקטים אשר יירשו מ-Object.prototype. הם מתודות ופרופ׳ אשר זמינים רק עבור ה-constructor Object עצמו. 

+ +
+

לתשומת לב:  זה נראה מוזר - כיצד יכולה להיות מתודה שמוגדרת על ה-constructor, שהיא בעצמה פונקציה? פונקציות הם גם סוג של אובייקט - ראו הדף בנושא ()Function להמשך פרטים.

+
+ +
    +
  1. אתם יכולים לבדוק את הפרופ׳ בשם ה-prototype של האובייקטים הנוכחיים שלנו - חזרו לדוגמא הקודמת והקלידו את הקוד הבא בקונסולה: +
    Person.prototype
    +
  2. +
  3. אתם לא תראו יותר מדי אפשרויות מכיוון שלא הגדרנו כלום בפרופ׳ בשם prototype של ה-constructor. כברירת מחדל, הפרופ׳ בשם prototype של ה-constructor תמיד מתחיל ריק.
  4. +
  5. כעת, נסו להזין את הקוד הבא: +
    Object.prototype
    +
  6. +
+ +

אתם תראו מספר גדול של מתודות שמוגדרות ב-property בשם prototype של Object, אשר זמינות עבור אובייקטים שירשו מ-Object כפי שהסברנו למעלה.

+ +

אתם תראו דוגמאות כאלו של שרשרת ההורשה - prototype chain inheritance בכל JavaScript - נסו לחפש אחר מתודות ופרופ׳ אשר מוגדרים בפרופ׳ של האובייקטים הגלובליים String, Date, Number, ו-Array. לכולם יש מס׳ מתודות ופרופ׳ שמוגדרות באותו prototype. זו הסיבה לדוגמא שכשאר אנחנו יוצרים מחרוזת בצורה הבאה:

+ +
var myString = 'This is my string.';
+ +

ל-myString ישר יש מספר מתודות שימושיות שזמינות עבורו כמו () split(), indexOf(), replace וכד׳. 

+ +
+

לתשומת לב: אנו ממליצים לקרוא את המדריך המעמיק שלנו בנושא - Using prototypes in JavaScript לאחר שהבנתם את החלק הזה. החלק הזה בכוונה נכתב בצורה פשוטה (יחסית) על מנת להסביר את הרעיון שעומד מאחורי הנושא.

+
+ +
+

חשוב: המאפיין (prototype (property הוא אחד מהחלקים המבלבלים ב-JavaScript. אתם עלולים לחשוב ש-this מצביע על האובייקט אב טיפוס של האובייקט הנוכחי, אבל הוא לא (זה אובייקט פנימי שניתן לגשת אליו באמצעות __proto__, זוכרים? ).

+ +

המאפיין prototype הוא בעצם property שמכיל אובייקט, אשר על אובייקט זה אנחנו מגדירים את המתודות והפרופ׳ שנרצו שיורשו.

+
+ +

שימוש במתודה ()create

+ +

מוקדם יותר ראינו כיצד מתודת ()Object.create יכולה לשמש על מנת ליצור אובייקט חדש:

+ +
    +
  1. לדוגמא, נסו להזין בקונסולה של הדוגמא הקודמת את הקוד הבא: +
    var person2 = Object.create(person1);
    +
  2. +
  3. מה ש-()create עושה בפועל היא ליצור אובייקט חדש מ-prototype מוגדר. כאן person2 מיוצר כאובייקט חדש באמצעות שימוש ב-person1 כאובייקט ה-prototype שלו, כאובייקט אב הטיפוס שלו. אתם יכולים לראות זאת באמצעות הזנת הקוד הבא בקונסולה:
  4. +
  5. +
    person2.__proto__
    +
  6. +
+ +

זה יחזיר לנו person1.

+ +

המאפיין (property) בשם constructor

+ +

לכל constructor function יש מאפיין (property) בשם prototype אשר הערך שלו הוא אובייקט. אותו אובייקט מכיל מאפיין (property) בשם constructor

+ +

המאפיין constructor הזה, מצביע ל-constructor function המקורית. כפי שתראו בהמשך, כאשר properties שמוגדרים על Person.prototype property, או באופן כללי, על המאפיין prototype של constructor function, שהוא בעצמו הוא אובייקט, הם נהיים זמינים עבור כל האובייקטים שייווצרו באמצעות ה-constructor בשם ()Person. המאפיין constructor זמין גם עבור האובייקט person1 וגם עבור האובייקט person2

+ +
    +
  1. לדוגמא, נסו להזין את השורות הבאות בקונסולה: +
    person1.constructor
    +person2.constructor
    + +

    שתיהן אמורות להחזיר לנו ה-Person() constructor, שכן היא מכילה את ה-״הגדרה״ המקורית של אובייקטים אלו. טריק חכם הוא שניתן לשים סוגריים רגילות () בסוף המאפיין constructor (ובתוך הסוגריים להכניס פרמרטים הנדרשים ל-constructor, ככל ונדרשים), וואז נוצר לנו אובייקט חדש מאותו constructor. ה-constructor הוא בעצם פונקציה אחרי הכל, אז אפשר לקרוא לפונקציה באמצעות שימוש ב-() כמו שאנחנו יודעים. רק חשוב לשים את המילה השמורה new לפני, על מנת להגדיר שאנחנו רוצים שיווצר אובייקט חדש ולהשתמש בפונקציה הזו כ-constructor של אותו אובייקט. 

    +
  2. +
  3. נסו להזין את הקוד הבא בקונסולה: +
    var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
    +
  4. +
  5. כעת, נסו לגשת למתודות ולפרופ׳ של האובייקט החדש: +
    person3.name.first
    +person3.age
    +person3.bio()
    +
  6. +
+ +

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

+ +

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

+ +
instanceName.constructor.name
+ +

נסו לדוגמא להזין את הקוד הבא:

+ +
person1.constructor.name
+
+ +
+

לתשומת לב:  הערך של constructor.name יכול להשתנות (כתוצאה מ-prototypical inheritance, binding, preprocessors, transpilers, etc. ועד), אז לדוגמאות מורכבות יותר, אנחנו נרצה להתשמש באופרטור instanceof במקום. 

+
+ +
    +
+ +

שינוי של הפרופ׳ בשם prototype - הוספה/הסרה של מתודות

+ +

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

+ +
    +
  1. חזרו לדוגמא המופיע בקישור oojs-class-further-exercises.htm וצרו עותק מקומי של קוד המקור source code. מתחת לקוד הנוכחי של של JavaScript, הוסיפו את הקוד הבא, אשר יוצר מתודה חדשה במאפיין prototype של constructor function:
  2. +
  3. +
    Person.prototype.farewell = function() {
    +  alert(this.name.first + ' has left the building. Bye for now!');
    +};
    +
  4. +
  5. שמרו את הקוד והעלו את הדף בדפדפן, ונסו להזין את הקוד הבא : +
    person1.farewell();
    +
  6. +
+ +

אתם אמורים לקבל הודעה קופצת מסוג alert, המכילה את שם ה-person שהוגדר ב-constructor. זה מאוד שימוש, אבל מה שיותר שימושי זה שכל שרשרת ההורשה עודכנה באופן דינאמי ואוטומטי והפכה את המתודה הזו לזמינה עבור כל האובייקטים שנוצרו באמצעות אותה constructor function. 

+ +

חשבו על זה לרגע, בקוד שלנו אנחנו הגדרנו את ה-constructor function, ואז יצרנו אובייקט מאותה constructor function, ואז הוספנו מתודה נוספות ל-prototype של אותה constructor function: 

+ +
function Person(first, last, age, gender, interests) {
+
+  // property and method definitions
+
+}
+
+var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']);
+
+Person.prototype.farewell = function() {
+  alert(this.name.first + ' has left the building. Bye for now!');
+};
+ +

ומה שקרה זה שהמתודה שהגדרנו ()farewell נהייתה זמינה עבור person1 - והוא יכול לעשות בה שימוש, למרות שהוא הוגדר לפני שהגדרנו את המתודה החדשה. מגניב, לא?

+ +
+

לתשומת לב: אם אתם נתקלים בבעיות, ראו את הדוגמא פה או כדף אינטרנט.

+
+ +

יחד עם זאת, לעיתים נדירות נראה properties שמוגדרים ב-property הprototype מכיוון שהם לא ממש גמישים כשהם מוגדרים בצורה הזו. לדוגמא, ניתן להוסיף property בצורה הזו: 

+ +
Person.prototype.fullName = 'Bob Smith';
+ +

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

+ +
Person.prototype.fullName = this.name.first + ' ' + this.name.last;
+ +

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

+ +

זה עובד מצוין על מתודה שהגדרנו למעלה ב-prototype מכיוון שהיא יושבת בתוך הסקופ של ה-function, והמתודה מועברת בתורה לסקופ של האובייקט שנוצר באמצעות constructor function. אז אולי נגדיר constant properties ב- prototype, כאלו שלא נשנה לעולם, אבל בכללי, זה עובד טוב יותר להגדיר properties בתוך ה-constructor. 

+ +

בעקרון, השימוש המקובל להגדרת אובייקטים הוא להגדיר את המאפיינים (properties) בתוך ה-constructor ואת המתודות בתוך ה-prototype. 

+ +

זה הופך הקוד לקל יותר לקריאה, שכן ה-constractor מכיל רק  את ההגדרות של properties ואילו המתודות מחולקות לבלוקים נפרדים. לדוגמא:

+ +
// Constructor with property definitions
+
+function Test(a, b, c, d) {
+  // property definitions
+}
+
+// First method definition
+
+Test.prototype.x = function() { ... };
+
+// Second method definition
+
+Test.prototype.y = function() { ... };
+
+// etc.
+ +

ניתן לראות שימוש בפועל בדוגמא school plan app של Piotr Zalewa.

+ +

לסיכום

+ +

מאמר זה כיסה את הנושא של JavaScript object prototypes, כולל כיצד prototype object chains מאפשרת לאובייקטים לירוש מתודות ופרופ׳ אחד מהשני, ראינו את ה-property בשם prototype וכיצד הוא יכול לשמש על מנת להוסיף מתודות ל-constructors וכן נושאים נוספים.

+ +

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

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}

+ +

במודול זה

+ + -- cgit v1.2.3-54-g00ecf