Skip to content

Commit 0f0ebe6

Browse files
committed
function prototype
1 parent 5084e2b commit 0f0ebe6

1 file changed

Lines changed: 220 additions & 75 deletions

File tree

  • 1-js/08-prototypes/02-function-prototype
Lines changed: 220 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
# F.prototype
1+
# الوراثة النموذجية -2-
22

3-
Remember, new objects can be created with a constructor function, like `new F()`.
3+
لا تنسَ بأنّك يمكنك إنشاء كائنات جديدة من خلال دالّة الباني (مثل `new F()‎ ‫`).
44

5-
If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object.
5+
لو كان `F.prototype` كائن جافاسكربت، فإن المعامِل `new` سيضبط الخاصية `[[Prototype]]` لهذا الكائن الجديد.
66

7-
```smart
8-
JavaScript had prototypal inheritance from the beginning. It was one of the core features of the language.
7+
من بداية تضمين لغة جافاسكربت للوراثة النموذجية جعلتها من المميزات الأساسية في اللغة.
8+
ولكن في الماضي لم يكن هنالك القدرة للوصول المباشر للوراثة النموذجية والطريقة الوحيدة الّتي حلّت محلها هي خاصية `"prototype"` في دالّة الباني. سنشرح في هذا الدرس كيفية استخدامها لأنه مازال العديد من الشيفرات البرمجية القديمة تستخدمها.
99

10-
But in the old times, there was no direct access to it. The only thing that worked reliably was a `"prototype"` property of the constructor function, described in this chapter. So there are many scripts that still use it.
11-
```
12-
13-
Please note that `F.prototype` here means a regular property named `"prototype"` on `F`. It sounds something similar to the term "prototype", but here we really mean a regular property with this name.
10+
لاحظ بأنّ `F.prototype` هنا تعني وجود خاصية عادية باسم `"prototype"` للكائن `F`. ربما تفكّر وكأنها النموذج الأولي لهذا الكائن، ولكن لا... فهنا نعني حرفيًا أنها خاصية عادية لها هذا الاسم.
1411

15-
Here's the example:
12+
إليك مثالًا:
1613

17-
```js run
14+
```
1815
let animal = {
1916
eats: true
2017
};
@@ -23,153 +20,301 @@ function Rabbit(name) {
2320
this.name = name;
2421
}
2522
26-
*!*
27-
Rabbit.prototype = animal;
28-
*/!*
23+
Rabbit.prototype = animal; // هنا
2924
3025
let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
3126
3227
alert( rabbit.eats ); // true
3328
```
3429

35-
Setting `Rabbit.prototype = animal` literally states the following: "When a `new Rabbit` is created, assign its `[[Prototype]]` to `animal`".
30+
تعني التعليمة `Rabbit.prototype = animal` حرفيًا الآتي: "ما إن يُنشأ كائن `new Rabbit`، أسنِد خاصية `[[Prototype]]` له لتكون للكائن `animal`".
3631

37-
That's the resulting picture:
32+
إليك الصورة الناتجة:
3833

39-
![](proto-constructor-animal-rabbit.svg)
34+
[proto-constructor-animal-rabbit.png]
4035

41-
On the picture, `"prototype"` is a horizontal arrow, meaning a regular property, and `[[Prototype]]` is vertical, meaning the inheritance of `rabbit` from `animal`.
36+
في الصورة نرى `"prototype"` في سهم أفقي (أي أنّها خاصية عادية) بينما `[[Prototype]]` في سهم رأسي (أي أنّها توضّح وراثة كائن `rabbit` للكائن `animal`).
4237

43-
```smart header="`F.prototype` only used at `new F` time"
44-
`F.prototype` property is only used when `new F` is called, it assigns `[[Prototype]]` of the new object.
38+
إن الخاصية `F.prototype` تستخدم عند الإنشاء فقط أي عندما تستدعى تعليمة `new F` وتُسند للكائن القيمة المناسبة للخاصية `[[Prototype]]`.
39+
في حال تغيرت الخاصية `F.prototype` مثلًا (`F.prototype = <another object>‎`)، عندها ستحصل الكائنات المنشأة بعد هذا التغيير على القيمة الجديدة للخاصية `[[Prototype]]` (أي الكائن الجديد)،
40+
ولكن الكائنات القديمة مازالت تحتفظ بالقيمة القديمة.
4541

46-
If, after the creation, `F.prototype` property changes (`F.prototype = <another object>`), then new objects created by `new F` will have another object as `[[Prototype]]`, but already existing objects keep the old one.
47-
```
48-
49-
## Default F.prototype, constructor property
42+
## القيمة الإفتراضية للخاصية prototype في الباني
5043

51-
Every function has the `"prototype"` property even if we don't supply it.
44+
لكلّ دالة خاصية `"prototype"` حتّى لو لم نقدّمها نحن.
5245

53-
The default `"prototype"` is an object with the only property `constructor` that points back to the function itself.
46+
إن القيمة الإفتراضية للخاصية `"prototype"` تُشير إلى نفس الدالّة.
5447

55-
Like this:
48+
هكذا تمامًا:
5649

57-
```js
50+
```
5851
function Rabbit() {}
5952
60-
/* default prototype
53+
/* كائن‫ prototype
6154
Rabbit.prototype = { constructor: Rabbit };
6255
*/
6356
```
6457

65-
![](function-prototype-constructor.svg)
58+
[function-prototype-constructor.png]
6659

67-
We can check it:
60+
يمكننا فحص ذلك أيضًا:
6861

69-
```js run
62+
```
7063
function Rabbit() {}
71-
// by default:
64+
// مبدئيًا:
7265
// Rabbit.prototype = { constructor: Rabbit }
7366
7467
alert( Rabbit.prototype.constructor == Rabbit ); // true
7568
```
7669

77-
Naturally, if we do nothing, the `constructor` property is available to all rabbits through `[[Prototype]]`:
70+
طبيعيًا، إن لم نعدل أي شيء، ستكون خاصية `constructor` مُتاحة لكلّ كائنات `rabbit` من خلال كائن `[[Prototype]]`:
7871

79-
```js run
72+
```
8073
function Rabbit() {}
81-
// by default:
74+
// مبدئيًا:
8275
// Rabbit.prototype = { constructor: Rabbit }
8376
84-
let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
77+
let rabbit = new Rabbit(); // ترث من‫ {constructor: Rabbit}
8578
86-
alert(rabbit.constructor == Rabbit); // true (from prototype)
79+
alert(rabbit.constructor == Rabbit); // true من prototype
8780
```
8881

89-
![](rabbit-prototype-constructor.svg)
82+
[rabbit-prototype-constructor.png]
9083

91-
We can use `constructor` property to create a new object using the same constructor as the existing one.
84+
يمكننا استعمال الخاصية `constructor` لإنشاء كائن جديد باستعمال نفس الباني الّذي أنشأ الكائن الموجود حاليًا.
9285

93-
Like here:
86+
هكذا:
9487

95-
```js run
88+
```
9689
function Rabbit(name) {
9790
this.name = name;
9891
alert(name);
9992
}
10093
10194
let rabbit = new Rabbit("White Rabbit");
10295
103-
*!*
96+
// انظر
10497
let rabbit2 = new rabbit.constructor("Black Rabbit");
105-
*/!*
10698
```
10799

108-
That's handy when we have an object, don't know which constructor was used for it (e.g. it comes from a 3rd party library), and we need to create another one of the same kind.
100+
يُفيدنا هذا حين نكون أمام كائن ولكن لا نعرف الباني الحقيقي الّذي بناه (ربما أتى من مكتبة خارجية)، وأردنا إنشاء كائن آخر مثله.
109101

110-
But probably the most important thing about `"constructor"` is that...
102+
ولكن الأمر الأهم الّذي يتعلّق بِـ `"constructor"` هو أنّ **لغة جافاسكربت نفسها لا تتأكّد من صحّة قيمة خاصية `"constructor"`.**
111103

112-
**...JavaScript itself does not ensure the right `"constructor"` value.**
104+
نعم كما قرأت، الخاصية موجودة في `"prototype"` للدوالّ، وهذا كلّ ما في الأمر. إذ ستعتمد لغة جافاسكربت علينا فيما سيحدث لاحقًا.
113105

114-
Yes, it exists in the default `"prototype"` for functions, but that's all. What happens with it later -- is totally on us.
106+
فمثلًا لو أردنا استبدال القيمة الإفتراضية للخاصية prototype، فلن يملك الكائن أيّ خاصية `"constructor"`.
115107

116-
In particular, if we replace the default prototype as a whole, then there will be no `"constructor"` in it.
108+
مثال:
117109

118-
For instance:
119-
120-
```js run
110+
```
121111
function Rabbit() {}
122112
Rabbit.prototype = {
123113
jumps: true
124114
};
125115
126116
let rabbit = new Rabbit();
127-
*!*
117+
// لاحظ
128118
alert(rabbit.constructor === Rabbit); // false
129-
*/!*
130119
```
131120

132-
So, to keep the right `"constructor"` we can choose to add/remove properties to the default `"prototype"` instead of overwriting it as a whole:
121+
ولهذا لنُبقي على خاصية `"constructor"` الصحيحة يمكننا إضافة الخاصيات وإزالتها من كائن `"prototype"` الإفتراضي بدل الطريقة السابقة. هكذا:
133122

134-
```js
123+
```
135124
function Rabbit() {}
136125
137-
// Not overwrite Rabbit.prototype totally
138-
// just add to it
126+
// بدل الكتابة على كلّ ‫Rabbit.prototype
127+
// نُضيف ما نريد إليه
139128
Rabbit.prototype.jumps = true
140-
// the default Rabbit.prototype.constructor is preserved
129+
// هكذا تبقى خاصية‫ Rabbit.prototype.constructor الإفتراضية محفوظة
141130
```
142131

143-
Or, alternatively, recreate the `constructor` property manually:
132+
أو يمكننا (لو أردنا) إعادة إنشاء الخاصية `constructor` يدويًا:
144133

145-
```js
134+
```
146135
Rabbit.prototype = {
147136
jumps: true,
148-
*!*
149-
constructor: Rabbit
150-
*/!*
137+
constructor: Rabbit // هنا
151138
};
152139
153-
// now constructor is also correct, because we added it
140+
// الآن سيكون المُنشِئ صحيحًا إذ أنّا من أضفناه
154141
```
155142

156143

157-
## Summary
144+
## خلاصة
158145

159-
In this chapter we briefly described the way of setting a `[[Prototype]]` for objects created via a constructor function. Later we'll see more advanced programming patterns that rely on it.
146+
شرحنا في هذا الفصل سريعًا طريقة ضبط كائن `[[Prototype]]` للكائنات الّتي أنشأتها بدالّة الباني. سنرى لاحقًا أنماط متقدّمة في البرمجة تعتمد على هذا الطريقة.
160147

161-
Everything is quite simple, just a few notes to make things clear:
148+
ما أخذناه بسيط، ولكن بعض الأمور نوضّحها ثانيةً للتأكّد:
162149

163-
- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called.
164-
- The value of `F.prototype` should be either an object or `null`: other values won't work.
165-
- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.
150+
- تضبط الخاصية `F.prototype` (لا تظنّها كائن `[[Prototype]]`) لكائنٍ ما الخاصية `[[Prototype]]` لكلّ الكائنات الجديدة متى استدعيت `new F()`.
151+
- يجب أن تكون قيمة `F.prototype` إمّا كائنًا أو `null`، ولن تعمل أيّة قيم أخرى.
152+
- هذا التأثير للخاصية `"prototype"` موجود فقط حين يُضبط في دالة الباني وحين يُنفّذ بتعليمة `new`.
166153

167-
On regular objects the `prototype` is nothing special:
168-
```js
154+
في الكائنات العادية ليست بخاصية خاصة جدًا:
155+
```
169156
let user = {
170157
name: "John",
171-
prototype: "Bla-bla" // no magic at all
158+
prototype: "Bla-bla" // نزعنا السحر
159+
};
160+
```
161+
162+
لكلّ الدوالّ مبدئيًا `F.prototype = { constructor: F }‎`، فيمكننا أن نأخذ باني معين من كائن ما بالدخول إلى الخاصية `"constructor"` الخاصة به.
163+
164+
## تمارين
165+
### تغيير الخاصية ”prototype“
166+
_الأهمية: 5_
167+
168+
أنشأنا في الشيفرة أدناه كائنًا جديدًا `new Rabbit` وحاولنا بعدها تعديل الخاصية prototype لهذا الكائن.
169+
170+
بادئ ذي بدء، كانت الشيفرة:
171+
172+
```
173+
function Rabbit() {}
174+
Rabbit.prototype = {
175+
eats: true
172176
};
177+
178+
let rabbit = new Rabbit();
179+
180+
alert( rabbit.eats ); // true
181+
```
182+
183+
184+
1. وأضفنا سلسلة نصية أخرى (عليها علامة). ماذا سيعرض التابِع `alert`؟
185+
186+
```
187+
function Rabbit() {}
188+
Rabbit.prototype = {
189+
eats: true
190+
};
191+
192+
let rabbit = new Rabbit();
193+
194+
Rabbit.prototype = {}; // (*)
195+
196+
alert( rabbit.eats ); // ?
197+
```
198+
199+
2. وماذا لو... كانت الشيفرة كهذه (استبدلنا سطرًا فيها)؟
200+
201+
```
202+
function Rabbit() {}
203+
Rabbit.prototype = {
204+
eats: true
205+
};
206+
207+
let rabbit = new Rabbit();
208+
209+
Rabbit.prototype.eats = false; // (*)
210+
211+
alert( rabbit.eats ); // ?
212+
```
213+
214+
3. وماذا عن هذه (استبدلنا سطرًا أيضًا)؟
215+
216+
```
217+
function Rabbit() {}
218+
Rabbit.prototype = {
219+
eats: true
220+
};
221+
222+
let rabbit = new Rabbit();
223+
224+
delete rabbit.eats; // (*)
225+
226+
alert( rabbit.eats ); // ?
227+
```
228+
229+
4. وهذه... أيضًا:
230+
231+
```
232+
function Rabbit() {}
233+
Rabbit.prototype = {
234+
eats: true
235+
};
236+
237+
let rabbit = new Rabbit();
238+
239+
delete Rabbit.prototype.eats; // (*)
240+
241+
alert( rabbit.eats ); // ?
242+
```
243+
#### الحل
244+
الإجابات:
245+
246+
1. `true`.
247+
248+
عملية الإسناد على `Rabbit.prototype` تضع الخاصية `[[Prototype]]` للكائنات الجديدة، ولكنّها لا تعدّل على الكائنات الموجودة مسبقًا.
249+
250+
2. `false`.
251+
عملية الإسناد تكون من خلال الخاصية `Rabbit.prototype`، إن الخاصية المشار إليها هنا `Rabbit.prototype` ليست مكررًا، وإنما بقيت يُشار إليها من خلال `Rabbit.prototype` و الخاصية `[[Prototype]]` للكائن `rabbit`.
252+
253+
لذا حين نغيّر المحتوى في الطريقة الأولى سنرى النتائج في الطريقة الثانية.
254+
255+
3. `true`.
256+
كلّ عمليات الحذف تطبق مباشرة على الكائن. تحاول هذه التعليمة `delete rabbit.eats` حذف الخاصية المخصصة للكائن `rabbit` ولكنها ليست لها. لذا العملية لن يكون لها أي تأثير.
257+
258+
259+
4. `undefined`.
260+
261+
حُذفت الخاصية `eats` من كائن prototype وما عادت موجودة بعد الآن.
262+
263+
### إنشاء كائن جديد من خلال نفس باني لكائنٍ آخر
264+
_الأهمية: 5_
265+
266+
تخيّل بأنّ لدينا الكائن الفريد `obj` وأنشأته بدالة الباني، ولكننا... لا نعرف أيّ دالة هذه، ولكن مع ذلك نريد استعمال نفس الباني لإنشاء كائن جديد آخر.
267+
268+
أيمكن لهذه الشيفرة إنجاز المهمة؟
269+
270+
```
271+
let obj2 = new obj.constructor();
272+
```
273+
274+
اكتب مثالين باستخدام بانيين للكائن `obj`، واحدًا يعمل مع الشيفرة أعلاه، وواحدًا لا يعمل له.
275+
#### الحل
276+
يمكن أن نستعمل هذه الطريقة لو كنّا متأكدين مئة بالمئة بأنّ خاصية `"constructor"` تحمل القيمة الصحيحة.
277+
278+
فمثلًا لو لم نعدّل على `"prototype"` المبدئية فستعمل هذه الشيفرة بلا ريب:
279+
280+
```
281+
function User(name) {
282+
this.name = name;
283+
}
284+
285+
let user = new User('John');
286+
let user2 = new user.constructor('Pete');
287+
288+
alert( user2.name ); // Pete (عملت!)
289+
```
290+
291+
نفذت الشيفرة تنفيذًا صحيحًا إذ أنّ `User.prototype.constructor == User`.
292+
293+
ولكن... لو أتى أحدهم مثلًا وكتب على `User.prototype` ونسي إعادة إنشاء `constructor` لتُشير إلى كائن المستخدم `User`، فلن تعمل الشيفرة.
294+
295+
مثال:
296+
297+
```
298+
function User(name) {
299+
this.name = name;
300+
}
301+
User.prototype = {}; // (*)
302+
303+
let user = new User('John');
304+
let user2 = new user.constructor('Pete');
305+
306+
alert( user2.name ); // undefined
173307
```
174308
175-
By default all functions have `F.prototype = { constructor: F }`, so we can get the constructor of an object by accessing its `"constructor"` property.
309+
لمَ قيمة `user2.name` هي `undefined`؟
310+
311+
إليك طريقة عمل تعليمة `new user.constructor('Pete')‎`:
312+
313+
1. أولًا، تبحث عن المُنشِئ `constructor` داخل `user`، ولا تجده.
314+
2. ثمّ تتبع سلسلة prototype وتجد prototype الكائن `user` هو `User.prototype`، وأيضًا لا تجده.
315+
3. قيمة `User.prototype` ما هي إلّا كائنًا فارغًا `{}`، و قيمة الخاصية prototype لهذا الكائن هي `Object.prototype`، وهنا وجدنا `Object.prototype.constructor == Object` بذلك استعملناه.
316+
317+
وفي نهاية الأمر، لدينا التعليمة `let user2 = new Object('Pete')‎` إذ أنّ الباني الخاص بالكائن `Object` يتجاهل الوسطاء وينشىء دائمًا كائنًا فارغًا. بطريقة مشابهة جدًا للتعليمة `let user2 = {}‎` والّتي أنشأت لنا الكائن `user2` في نهاية الأمر.
318+
319+
ترجمة -وبتصرف- للفصل [F.prototype](https://javascript.info/function-prototype) من كتاب [The JavaScript language](https://javascript.info/js)
320+

0 commit comments

Comments
 (0)