1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
|
---
title: مدخل إلى جافاسكريبت كائنية التوجه
slug: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
tags:
- الأفراد
- البرمجة الكائنية
- التغليف
- الجافاسكريبت
- المتوسط
- المجال
- المشيد
- ب.ك.ت
- كائن
translation_of: Learn/JavaScript/Objects
---
<div>{{jsSidebar("Introductory")}}</div>
<p>كائنية التوجه حتى النخاع، ميزات جافا سكريبت القوية، القدرات المرنة {{Glossary("OOP")}}. يبدأ هذا المقال بمقدمة إلى البرمجة الكائنية التوجه، ثم مراجعات لنموذج كائن جافا سكريبت، و أخيراً يوضح مفاهيم البرمجة الكائنية التوجه في جافا سكريبت. لا يصف هذا المقال البناء اللغوي الجديد <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">للبرمجة الكائنية التوجه في ECMAScript 6</a>.</p>
<div style="font-size: 15; font-family: 'tahoma';">
<h2 id="مراجعة_جافا_سكريبت">مراجعة جافا سكريبت</h2>
<p>إذا كنت لا تشعر بالثقة حول مفاهيم جافا سكريبت مثل المتغيرات والأنواع والوظائف و المجال ، يمكنك ان تقرأ عن هذه المواضيع في <a href="/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript">مدخل إلى جافا سكريبت</a>. يمكنك أيضا الاطلاع علي <a href="/en-US/docs/Web/JavaScript/Guide">دليل جافا سكريبت</a>.</p>
<h2 id="البرمجة_الكائنية_التوجه_(Object-oriented_programming)">البرمجة الكائنية التوجه (Object-oriented programming)</h2>
<p>إن البرمجة الكائنية (OOP) ما هي إلا نمط برمجي يَستخدم التجريد في إنشاء نماذج/نسخ لتجسيد العالم الحقيقي، وتَستخدم البرمجة الكائنية في ذلك أساليب مُتعدّدة من هذا النمط، فهي تستخدم الوحدات module، وتعدديّة الأشكال polymorphism والتغليف encapsulation، وتجدر الإشارة إلى أن معظم لغات البرمجة تدعم مفهوم OOP أمثال اللغات البرمجية: جافا، بايثون، روبي، وطبعًا جافا سكريبت.</p>
<p>يُعالج أو لنقل يَتصور مفهوم البرمجة الكائنية OOP البرنامج كتشكيلة من الأشياء/الكائنات المتعاونة/المترابطة بدلًا من يتصوّره كتشكيلة من الدوال (functions) أو كسرد من الأوامر. ففي مفهوم OOP، كل كائن/شيء له القدرة على استقبال الرسائل، ومعالجة البيانات، وإرسال الرسائل إلى باقي الكائنات، ويُمكن اعتبار أنه لكل كائن object كينونة خاصة به ودور/وظيفة مستقلة عن الكائن الآخر.</p>
<p>تُعزز البرمجة الكائنية القدرة على صيانة الشيفرة البرمجية والمرونة في التطوير، وأثبتت جدارتها على نطاق واسع في هندسة البرمجيات الكبيرة، ولأن البرمجة الكائنية تُشدد على استخدام الوحدات module، فإن الشيفرة/الكود المكتوب بمفهوم البرمجة الكائنية هو أبسط في التطوير وأسهل في الفهم مستقبلًا (عند التنقيح والتعديل)، وكما يعزز مفهوم البرمجة الكائنية التحليل المباشر للشيفرة، وفهم الحالات الشائكة فهمًا أفضل من باقي الأساليب البرمجية الأخرى.</p>
<h2 id="مصطلحات_البرمجة_الكائنية">مصطلحات البرمجة الكائنية</h2>
<dl>
<dt dir="ltr">
<h3 dir="rtl" id="المجال_في_البرمجة_الكائنية_Namespace">المجال في البرمجة الكائنية Namespace</h3>
<p dir="rtl">ما هو إلا عبارة عن حاوي تسمح للمطوّر بتحزيم جميع الوظائف تحت اسم محدد وفريد.</p>
<h3 dir="rtl" id="الصنف_أو_الفئة_Class_في_البرمجة_الكائنية">الصنف أو الفئة Class في البرمجة الكائنية</h3>
<p dir="rtl">يعتني الصنف بكل ما يتعلّق بميزات وخصائص الكائن، والصنف ما هو إلا قالب template تعريفي بخاصيات properties وبطُرق/وظائف methods الكائن object.</p>
<h3 dir="rtl" id="الكائن_Object_في_البرمجة_الكائنية">الكائن Object في البرمجة الكائنية</h3>
<p dir="rtl">الكائن ما هو إلا حالة/أمثولة instance من صنف class.</p>
<h3 dir="rtl" id="الخاصية_property_في_البرمجة_الكائنية">الخاصية property في البرمجة الكائنية</h3>
<p dir="rtl">ما هي إلا مميزات وخصائص الكائن، كاللون مثلًا.</p>
<h3 dir="rtl" id="الطريقة_أو_الوظيفة_Method_في_البرمجة_الكائنية">الطريقة أو الوظيفة Method في البرمجة الكائنية</h3>
<p dir="rtl">تعتني الطريقة أو الوظيفة كما يُسميها البعض بقدرات الكائن، مثل قدرة المشي مثلًا، وهي دور أو وظيفة مرتبطة مع صنف class.</p>
<h3 dir="rtl" id="المشيد_Constructor_في_البرمجة_الكائنية">المشيد Constructor في البرمجة الكائنية</h3>
<p dir="rtl">ما هو إلا طريقة method تُستدعى في لحظة استهلال instantiate الكائن، وعادةً ما يكون له نفس اسم الصنف الذي يحتويه.</p>
<h3 dir="rtl" id="الوراثة_Inheritance_في_البرمجة_الكائنية">الوراثة Inheritance في البرمجة الكائنية</h3>
<p dir="rtl">يُمكن للصنف أن يرث مميزات من صنف آخر.</p>
<h3 dir="rtl" id="التغليف_Encapsulation_في_البرمجة_الكائنية">التغليف Encapsulation في البرمجة الكائنية</h3>
<p dir="rtl">طريقة في تحزيم البيانات data والطُرق methods التي تستخدم البيانات.</p>
<h3 dir="rtl" id="التجريد_Abstraction_في_البرمجة_الكائنية">التجريد Abstraction في البرمجة الكائنية</h3>
<p dir="rtl">يجب على الاقتران الحاصل من: الوراثة والطُرق methods والخاصيات properties لكائن معقد وشائك التمثيل برمجيًا أن يعكس الواقع المراد محاكاته في البرمجة الكائنية.</p>
<h3 dir="rtl" id="تعددية_الأشكال_Polymorphism_في_البرمجة_الكائنية">تعددية الأشكال Polymorphism في البرمجة الكائنية</h3>
<p dir="rtl">تحمل كلمة Poly بحد ذاتها المعنى "متعدد" وتحمل الكلمة morphism المعنى "أشكال، ويُشير المفهوم ككل إلى أن أكثر من صنف قد يُعرّف نفس الطريقة method أو الخاصية property.</p>
</dt>
</dl>
<p>للحصول على وصف أكثر شمولية للبرمجة الكائنية التوجه، أنظر {{interwiki("wikipedia", "البرمجة كائنية التوجه")}} على ويكيبيديا.</p>
<h2 id="البرمجة_المعتمدة_على_النموذج_الأولي_Prototype">البرمجة المعتمدة على النموذج الأولي Prototype</h2>
<p>البرمجة المعتمدة على النموذج الأوّلي (Prototype-based programming) ما هي إلا نموذج من البرمجة الكائنية OOP ولكنها لا تستخدم الأصناف classes، بل تقوم أولًا بإعداد سلوك أي صنف class ما ومن ثم تُعيد استخدامه، ويُطلق البعض على هذا النموذج: البرمجة بلا أصناف classless، أو البرمجة المَبْدَئِية المنحى prototype-oriented، أو البرمجة المعتمدة على الأمثولة instance-based).</p>
<p>يعود أصل اللغة المعتمدة على النموذج الأولي إلى لغة <a href="http://en.wikipedia.org/wiki/Self%20(programming%20language" rel="external nofollow noopener noreferrer">Self</a>، والتي طوّرها David Ungar وRandall Smith، ولكن أسلوب البرمجة بدون أصناف class-less توسّع ونال شهرة كبيرة في العقد الأخير، واُعتمد من قبل العديد من اللغات البرمجية أشهرهم جافا سكريبت.</p>
<p dir="ltr"> </p>
<h2 id="البرمجة_الكائنية_باستخدام_جافا_سكريبت">البرمجة الكائنية باستخدام جافا سكريبت</h2>
<h3 id="المجال_Namespace_في_جافا_سكريبت">المجال Namespace في جافا سكريبت</h3>
<p>المجال هو أشبه بمستوعب/بحاوية (container) تسمح للمطوّر في تحزيم وظائف تحت اسم فريد، أو اسم تطبيق محدد، ففي جافا سكريبت المجال هو مجرد كائن object كأي كائن آخر يحتوي على طُرق methods، وخاصيات properties، وحتى كائنات objects.</p>
<div class="note">
<p><strong>ملاحظة هامة</strong>: من المهم جدًا الانتباه إلى أنه في جافا سكريبت، لا يوجد فرق بين الكائنات العادية والمجالات namespaces، وهذا يختلف عن اللغات الكائنية الأخرى، الأمر الذي قد يُربك المبرمجين المبتدئين في جافا سكريبت.</p>
</div>
<p>إن إنشاء مجال namespace في جافا سكريبت بسيطٌ للغاية، فمن خلال إنشاء كائن عام/مشترك/شامل global، ستصبح جميع المُتغيّرات variables والطرق methods، والدوال functions خاصياتٍ لهذا الكائن، ويٌقلل استخدام المجالات namespaces أيضًا من احتمالية تضارب الأسماء في التطبيق، منذ أن كل كائن من كائنات التطبيق ما هي إلى خاصيات كائن شامل/عام معرّفة على مستوى التطبيق.</p>
<p>سيُنشئ في الخطوة التالية كائنًا عامًا global وبالاسم <code>MYAPP</code>:</p>
<pre class="brush: js" dir="rtl">// مجال عالمي
var MYAPP = MYAPP || {};</pre>
<p>يُظهر المثال السابق، كيف تم التأكّد أولًا فيما إذا كان <code>MYAPP</code> معرفًا (سواء في نفس الملف أو في آخر)، ففي حال الإيجاب سيُستخدم الكائن العام <code>MYAPP</code>، وفي حال عدم تعريفه مُسبقًا سيُنشئ كائنًا خالٍ وبالاسم<code>MYAPP</code> والذي سيغلّف encapsulate الطرق methods والدوال functions والمتغيرات variables والكائنات objects.</p>
<p>كما يُمكن أيضًا إنشاء مجال فرعي sub-namespaces:</p>
<pre class="brush: js" dir="rtl">// مجال فرعي
MYAPP.event = {};</pre>
<p>يوضّح المثال التالي الصيغة المستخدمة في إنشاء مجال namespace وإضافة متغيرات ودوال:</p>
<pre class="brush: js" dir="rtl">// إنشاء حاوي يدعى MYAPP.commonMethod للوظائف و الخصائص الشائعة
MYAPP.commonMethod = {
regExForName: "", // تعريف تعبير نظامي للتحقق من الإسم
regExForPhone: "", // تعريف تعبير نظامي للهاتف، لا يوجد تحقق من الصحة
validateName: function(name){
// إفعل شيئا ما بالإسم، يمكنك الوصول إلى المتغير regExForName
// بإستعمال "this.regExForName"
},
validatePhoneNo: function(phoneNo){
// إفعل شيئا ما برقم الهاتف
}
}
// تعريفات الكائن مع الزظيفة في نفس الوقت
MYAPP.event = {
addListener: function(el, type, fn) {
// بعض الأكواد
},
removeListener: function(el, type, fn) {
// بعض الأكواد
},
getEvent: function(e) {
// بعض اﻷكواد
}
// يمكن إضافة وظائف و خصائص أخرى
}
// البناء اللغوي لإستعمال وظيفة addListener:
MYAPP.event.addListener("yourel", "type", callback);</pre>
<h3 id="sect1"> </h3>
<h3 id="الكائنات_الأساسيةالقياسية_المبنية_داخل_لغة_جافا_سكريبت_(Standard_built-in_objects)">الكائنات الأساسية/القياسية المبنية داخل لغة جافا سكريبت (Standard built-in objects)</h3>
<p>تتضمن لغة جافا سكريبت العديد من الكائنات في تركيبتها، على سبيل المثال، يوجد كائنات مثل <code>Math</code>،<code>Object</code>، <code>Array</code>، <code>String</code>، ويُظهر المثال التالي كيفيّة استخدام الكائن <code>Math</code> للحصول على رقم عشوائي باستخدام أحد طُرق method هذا الكائن وهي الطريقة ()<code>random</code>.</p>
<pre class="brush: js" dir="rtl">console.log(Math.random());
</pre>
<div class="note">
<p><strong>ملاحظة</strong>: يَفترض المثال السابق وجميع الأمثلة التالية في المقال وجود دالة function بالاسم()<code>console.log</code> معرّفة تعريفًا عامًا (globally)، مع العلم أن هذه الدالة ليست جزء من اللغة نفسها، ولكنها دالة متوفّرة في العديد من متصفحات الإنترنت لأغراض تشخيص الشيفرة البرمجية debugging.</p>
</div>
<p>يُمكن العودة إلى <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects" rel="external nofollow noopener noreferrer">مرجع لغة جافا سكريبت: الكائنات الأصلية المعيارية</a> للحصول على قائمة بالكائنات المبينة داخل لغة جافا سكريبت نفسها.</p>
<p>كل كائن في جافا سكريبت هو حالة/أمثولة instance من الكائن <code>Object</code> ويَرث كافة خاصياته properties وطُرقه methods.</p>
<h3 id="sect2"> </h3>
<h3 id="الكائنات_الخاصة_الصنف_(الفئة)">الكائنات الخاصة<br>
<span style='font-family: "Open Sans Light",Helvetica,Arial,sans-serif; font-size: 1.286rem; letter-spacing: -0.014em;'>الصنف (الفئة</span><span style='font-family: "Open Sans Light",Helvetica,Arial,sans-serif; font-size: 1.286rem; letter-spacing: -0.014em;'>)</span></h3>
<h4 id="لغة_جافا_سكريبت_لغة_من_النوع_prototype-based_ولا_تحتوي_على_العبارة_class_كما_هو_حال_باقي_لغات_البرمجة_الكائنية،_كما_في_روبي_أو_بايثون،_ويُربك_هذا_الأمر_المبرمجين_المعتادين_على_اللغات_التي_تعتمد_على_هذه_العبارة_أو_المفهوم،_وتستخدم_جافا_سكريبت_بدلًا_من_ذلك_الدوال_functions_لمحاكات_مفهوم_الأصناف_classes،_وتعريف_صنف_هو_بسهولة_تعريف_أي_دالّة">لغة جافا سكريبت لغة من النوع prototype-based ولا تحتوي على العبارة <code>class</code> كما هو حال باقي لغات البرمجة الكائنية، كما في روبي أو بايثون، ويُربك هذا الأمر المبرمجين المعتادين على اللغات التي تعتمد على هذه العبارة أو المفهوم، وتستخدم جافا سكريبت بدلًا من ذلك الدوال functions لمحاكات مفهوم الأصناف classes، وتعريف صنف هو بسهولة تعريف أي دالّة:</h4>
<pre class="brush: js" dir="rtl">var Person = function () {};
</pre>
<h4 id="الكائن_(أمثولة_الصنف_class_instance)">الكائن (أمثولة الصنف class instance)</h4>
<p>يتطلب إنشاء حالة/أمثولة instance جديدة من كائن <code>obj</code> استخدام العبارة <code>new obj</code>، وتعيين النتيجة إلى متغيّر بغرض الوصول إلى فيما بعد.</p>
<p>عُرّف في الشيفرة السابقة صنف class بالاسم <code>Person</code>، وفي الشيفرة التالية، سيُنشئ حالتين/أمثولتين instances من هذا الصنف، الأولى بالاسم <code>person1</code> والثانية بالاسم <code>person2</code>.</p>
<pre class="brush: js" dir="rtl">var person1 = new Person();
var person2 = new Person();
</pre>
<div class="note">فضلا أنظر {{jsxref("Object.create()")}} للحصول على وظيفة الإنشاء الجديدة الإضافية التي تنشأ حالة غير مهيأة</div>
<h4 id="المشيد_The_constructor">المشيد The constructor</h4>
<p>يُستدعى المُشيّد constructor في لحظة الاستهلال instantiation (اللحظة التي يُنشئ فيها الكائن)، والمُشيّد ما هو إلا طريقة method من طُرق الصنف class، وفي جافا سكريبت تعمل الدالة على تشييد الكائن، ولذلك لا داعي إلى تعريف طريقة method من أجل عميلة التشييد، وكل إجراء مصرّح في الصنف class يُنفّذ في لحظة الاستهلال instantiation.</p>
<p>يُستخدم المُشيّد في تعيين خاصيات properties الكائن، أو في استدعاء طُرق methods معينة لتحضير الكائن للاستخدام، وأما إضافة طُرق صنف وتعريفها يحدث باستخدام صيغة syntax مختلفة سنتطرّق إليها فيما بعد خلال المقال.</p>
<p>تُظهر الشيفرة التالية كيف يُسجّل log (يُرسل رسالة نصية إلى طرفية المتصفح console) مُشيّد الصنف<code>Person</code> رسالة نصية حينما يُستهل instantiated.</p>
<pre class="brush: js" dir="rtl">var Person = function () {
console.log('تم إنشاء حالة');
};
var person1 = new Person();
var person2 = new Person();
</pre>
<h4 id="الخاصية_The_property_(خاصية_الكائن_object_attribute)">الخاصية The property (خاصية الكائن object attribute)</h4>
<p>الخاصيات properties ما هي إلا متغيرات محتوات في الصنف class، وكل حالة/أمثولة من الكائن تمتلك هذه الخاصيات، وتُعيّن الخاصيات في دالة مُشيّد الصنف بحيثُ تُنشئ مع كل حالة/أمثولة instance.</p>
<p>إن الكلمة المفتاحية <code>this</code>، والتي تُشير إلى الكائن الحالي، تسمح للمطوّر بالعمل مع الخاصيات من ضمن الصنف، والوصول (قراءةً وكتابةً) إلى الخاصية property من خارج الصنف يكون من خلال الصيغة<code>InstanceName.Property</code> كما هو الأمر في لغة C++ (سي بلس بلس) وJava والعديد من اللغات الأخرى، ومن داخل الصنف تُستخدم الصيغة <code>this.Property</code> للحصول على قيمة الخاصية أو لتعيين قيمتها.</p>
<p>في الشيفرة التالية، عُرّفت الخاصية <code>firstName</code> للصنف <code>Person</code> وفي لحظة الاستهلال instantiation:</p>
<pre class="brush: js" dir="rtl">var Person = function (firstName) {
this.firstName = firstName;
console.log('تم إنشاء حالة من Person');
};
var person1 = new Person('سفيان');
var person2 = new Person('محمد');
// Show the firstName properties of the objects
console.log('الشخص1 هو ' + person1.firstName); // النتيجة ==> "الشخص1 هو سفيان"
console.log('الشخص2 هو ' + person2.firstName); // النتيجة ==> "الشخص2 هو محمد"
</pre>
<h4 id="الطرق_The_methods">الطرق The methods</h4>
<p>الطرق methods ما هي إلا دوال (وتُعرّف كما تعرّف الدوال functions)، فيما عدا ذلك فهي تُشبه الخاصيات properties، واستدعاء طريقة method مشابه إلى الوصول إلى خاصيّة ما، ولكن مع إضافة <code>()</code> في نهاية اسم الطريقة، وربما مع مُعطيات arguments، ولتعريف طريقة، تُعيّن دالة إلى خاصيّة مُسمّات من خاصيّة الصنف <code>prototype</code>، ويُمكن فيما بعد استدعاء الطريقة على الكائن بنفس الاسم الذي عُيّن للدالة.</p>
<p>في الشيفرة التالية، عُرّفت ومن ثم اُستخدِمت الطريقة ()<code>sayHello</code> للصنف <code>Person</code>.</p>
<pre class="brush: js" dir="rtl">var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("مرحبا، أنا " + this.firstName);
};
var person1 = new Person("سفيان");
var person2 = new Person("محمد");
// إستدعاء طريقة Person sayHello.
person1.sayHello(); // النتيجة ==>"مرحبا، أنا سفيان"
person2.sayHello(); // النتيجة ==> "مرحبا، أنا محمد"
</pre>
<p>إن الطُرق methods في جافا سكريبت ما هي إلا دالة كائن عادية مرتبطة مع كائن كخاصية property، وهذا يعني أنه يُمكن استدعاء الطُرق خارج السياق، كما في المثال التالي:</p>
<pre class="brush: js" dir="rtl">var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("مرحبا، أنا " + this.firstName);
};
var person1 = new Person("سفيان");
var person2 = new Person("محمد");
var helloFunction = person1.sayHello;
// النتيجة ==> "مرحبا، أنا سفيان"
person1.sayHello();
// النتيجة ==> "مرحبا، أنا محمد"
person2.sayHello();
// النتيجة ==> "مرحبا، أنا undefined" (أو أخطاء
// TypeError في الوضع الصارم)
helloFunction();
// النتيجة ==> true
console.log(helloFunction === person1.sayHello);
// النتيجة ==> true
console.log(helloFunction === Person.prototype.sayHello);
// النتيجة ==> "مرحبا، أنا سفيان"
helloFunction.call(person1);</pre>
<p>كما يُظهر المثال السابق، جميع الإحالات المستخدمة في استدعاء الدالة <code>sayHello</code> تُشير إلى <strong><em>نفس الدالة</em></strong>سواءً الاستدعاء الحاصل مع <code>person1</code> أو <code>Person.prototype</code> أو حتى في المتغيّر <code>helloFunction</code>وقيمة <code>this</code> خلال استدعاء الدالة يعتمد على الكيفية التي تُستدعى فيها، حيث تُشير الكلمة المفتاحية<code>this</code> إلى الكائن الحالي الذي تُستدعى عليه الطريقة method، بمعنى عندما تم استدعاء الطريقة()<code>sayHello </code>على الكائن <code>person1</code> فإن <code>this</code> تُشير إلى الكائن <code>person1</code>، وعند استدعاء <code>sayHello</code>على الكائن <code>person2</code> فإن <code>this</code> تُشير إلى الكائن <code>person2</code>، ولكن إن تم الاستدعاء بطريقة مختلفة، فإن<code>this</code> ستُعيّن تعينًا مختلفًا، فاستدعاء <code>this</code> من المتغيّر (كما في ()<code>helloFunction</code>) سيُعيّن <code>this</code> إلى الكائن العام global (والذي سيكون window في متصفح الإنترنت)، ومنذ أن هذا الكائن (على الأغلب) لا يملك الخاصّيّة <code>firstName</code>، ستكون النتيجة كما هو الحال في المثال السابق “Hello, I’m undefined”، كما يمكن دائمًا تعيين <code>this</code> صراحةً باستخدام <code>Function#call</code> (أو <code>Function#apply</code>) وهو كما كان في نهاية المثال.</p>
<div class="note"><strong>ملاحظة:</strong> أنظر المزيد حول <code>this</code> على <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call">call</a> و <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply">apply</a></div>
<h4 id="الوراثة">الوراثة</h4>
<p>تُستخدم الوراثة في جافا سكريبت في إنشاء صنف class كمثيل مخصص لصنف أو أكثر (<strong><em>تدعم جافا سكريبت وراثة وحيدة فقط single inheritance</em></strong>)، ويُطلق على الصنف المخصص عادةً <strong><em>ابن</em></strong> (child)، ويطلق على الصنف الآخر عادةً <strong><em>الأب</em></strong> (parent)، وفي جافا سكريبت يتمّ ذلك من خلال إسناد حالة/أمثولة من الصنف الأب إلى الصنف الابن، ومن ثم تخصيصه، وفي متصفحات الإنترنت الحديثة يُمكن استخدام<code>Object.create</code> في تحقيق الوراثة inheritance أيضًا.</p>
<div class="note" dir="ltr">
<p dir="rtl"><strong>ملاحظة</strong>: لا تتفقد جافا سكريبت مُشيّد صنف الابن <code>prototype.constructor</code> (راجع<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype" rel="external nofollow noopener noreferrer"><code>Object.prototype</code></a>)، وعليه يجب التصريح عن ذلك يدويًا، لمزيد من التفصيل راجع السؤال التالي على<a href="http://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor" rel="external nofollow noopener noreferrer">Stackoverflow</a>.</p>
</div>
<p>عُرّف في الشيفرة التالية الصنف <code>Student</code> كصنف ابن للصنف <code>Person</code>، ومن ثم أُعيد تعريف الطريقة()<code>sayHello</code> وأُضيفت الطريقة ()<code>sayGoodBye</code> علاوة على ذلك.</p>
<pre class="brush: js" dir="rtl">// تعريف المشيد Person
var Person = function(firstName) {
this.firstName = firstName;
};
// إضافة زوج من الطرق إلى Person.prototype
Person.prototype.walk = function(){
console.log("أنا أتمشى!");
};
Person.prototype.sayHello = function(){
console.log("مرحبا، أنا " + this.firstName);
};
// تعريف مشيد Student
function Student(firstName, subject) {
// إستدعاء المشيد اﻷب, التأكد (عن طريق الإستدعاء)
// من أن "this" وضعت بشكل صحيح أثناء اﻹستدعاء
Person.call(this, firstName);
// تهيئة خصائص الطالب المحددة
this.subject = subject;
}
// إنشاء كائن Student.prototype الذي يرث من Person.prototype.
// ملاحظة: خطأ شائع أن يستعمل "new Person()" ﻹنشاء
// Student.prototype. هذا غير صحيح لعدة أسباب،
// ليس أقل أننا ليس لدينا أي شيء ﻹعطاء Person إلى المعامل "firstName".
// الطريقة الصحيحة ﻹستدعاء Person هي في الأعلى حيث
// إستدعيناه من Student.
Student.prototype = Object.create(Person.prototype); // See note below
// وضع الخاصية "constructor" للإشارة إلى Student
Student.prototype.constructor = Student;
// إستبدال الطريقة "sayHello"
Student.prototype.sayHello = function(){
console.log("مرحبا، أنا " + this.firstName + ". أنا أدرس "
+ this.subject + ".");
};
// إضافة الطريقة "sayGoodBye"
Student.prototype.sayGoodBye = function(){
console.log("وداعا!");
};
// إستعمال المثال:
var student1 = new Student("سفيان", "المناجم");
student1.sayHello(); // "مرحبا، أنا سفيان. أنا أدرس المناجم."
student1.walk(); // "أنا أتمشى!"
student1.sayGoodBye(); // "وداعا!"
// التحقق من أن instanceof يعمل بشكل صحيح
console.log(student1 instanceof Person); // true
console.log(student1 instanceof Student); // true
</pre>
<p>فيما يخص السطر ;(<code>Student.prototype = Object.create(Person.prototype</code> في الإصدارات القديمة من جافا سكريبت والتي لا تدعم <code>Object.create</code> يمكن إما استخدام بعض الحيل في خداع المتصفحات –هذه الخدع معروفة إما بالاسم polyfill أو shim—أو استخدام دالة تحقق نفس النتيجة كما في المثال التالي:</p>
<pre class="brush: js" dir="rtl">function createObject(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor();
}
// الإستعمال:
Student.prototype = createObject(Person.prototype);
</pre>
<div class="note"><strong>ملاحظة:</strong> أنظر <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a> للمزيد من المعلومات حول ما يقوم به, و الرقاقات للمحركات القديمة.</div>
<p>التأكّد من أن <code>this</code> تُشير إلى الكائن المطلوب بغض النظر عن كيف للكائن أن يُستهل يمكن أن يكون صعبًا، ومع ذلك يوجد صياغة أبسط من شأنها أن تسهّل الأمر.</p>
<pre class="brush: js" dir="rtl">var Person = function(firstName) {
if (this instanceof Person) {
this.firstName = firstName;
} else {
return new Person(firstName);
}
}
</pre>
<h4 id="التغليف_Encapsulation">التغليف Encapsulation</h4>
<p>ليس بالضرورة أن يعلم الصنف <code>Student</code> كيف تمّ تنفيذ/تعريف الطريقة ()<code>walk</code> للصنف <code>Person</code> لكي يستطيع استخدام تلك الطريقة، ولا يحتاج الصنف <code>Student</code> إلى تعريف تلك الطريقة صراحةً إلا إذا كان المطلوب التعديل عليها، ويُطلق على هذا الإجراء مفهوم التغليف encapsulation، والذي فيه يَحزم كل صنف البيانات والطُرق methods داخل وحدة/كينونة وحيدة.</p>
<p>إخفاء المعلومات سمة شائعة في باقي اللغات البرمجية وعادةً ما توجد كخاصيات/كطُرق إما بالاسم<code>private</code> أو <code>protected</code>، وعلى الرغم من أنه يُمكن مماثلة/محاكاة ذات الأمر في جافا سكريبت، إلا أن هذا الأمر ليس مطلبًا من متطلبات البرمجة الكائنية.</p>
<h4 id="التجريد_Abstraction">التجريد Abstraction</h4>
<p>التجرير ما هو إلا ميكانيكية تسمح للمطوّر في تجسيد جانب من المشكلة التي يُعمل عليها، إما من خلال الوراثة inheritance (التخصيص specialization) أو التركيب composition، وتُحقق جافا سكريبت التخصيص من خلال الوراثة، والتركيب من خلال السماح لحالات/أمثولات الصنف لتكون قيمًا لخاصيات attributes الكائنات الأخرى.</p>
<p>الصنف Function في جافا سكريبت يرث من الصنف <code>Object</code> (وهذا يوضّح التخصيص في هذا النموذج) والخاصية <code>Function.prototype</code> ما هي إلا حالة/أمثولة من الصنف <code>Object</code> (وهذا يوضّح جزئية التركيب composition).</p>
<pre class="brush: js" dir="rtl">var foo = function () {};
// النتيجة ==> "foo عبارة عن وظيفة: true"
console.log('foo عبارة عن وظيفة: ' + (foo instanceof Function));
// النتيجة ==> "foo.prototype عبارة عن كائن: true"
console.log('foo.prototype عبارة عن كائن: ' + (foo.prototype instanceof Object));</pre>
<h4 id="تعددية_الأشكال_Polymorphism">تعددية الأشكال Polymorphism</h4>
<p>كما أن جميع الطُرق methods والخاصيات properties معرّفة ضمن الخاصية prototype، فيُمكن لبقية الأصناف أن تُعرِّف طُرقًا methods بنفس الاسم، وستكون الطُرق في نطاق الصنف الذي عُرفت به، إلا إذا كان الصنفان على علاقة من نوع أب وابن parent-child، بمعنى آخر أحد الصنفان يرث من الآخر<br>
<br>
هذه المقالة تُرجمة الي العربية بواسطة : <a href="https://academy.hsoub.com/profile/12-%D9%85%D8%AD%D9%85%D8%AF-%D8%A3%D8%A8%D8%B1%D8%B5/" id="ips_uid_2904_3" title="الذّهاب إلى الملف الشّخصي لعضو : محمد أبرص">محمد أبرص</a></p>
<h2 id="ملاحظات">ملاحظات</h2>
<p>هذه ليست الطرق الوحيدة التي يمكنك من خلالها تنفيذ البرمجة الشيئية في جافا سكريبت ، والتي تعد مرنة للغاية في هذا الصدد. وبالمثل ، فإن التقنيات الموضحة هنا لا تستخدم أي لغة خارقة ، ولا تحاكي تطبيقات اللغات الأخرى لنظرية الكائن.</p>
<p>هناك تقنيات أخرى تجعل البرمجة الكائنية التوجه أكثر تقدما لكنها خارج نطاق الهذه المقالة التمهيدية.</p>
</div>
<h2 id="المراجع">المراجع</h2>
<ol>
<li><a href="https://ar.wikipedia.org/wiki/Object-oriented_programming" id="cite-1">ويكيبيديا - البرمجة الكائنية التوجه</a></li>
<li><a href="https://en.wikipedia.org/wiki/Prototype-based_programming" id="cite-2">ويكيبيديا - البرمجة القائمة على النوذج</a></li>
<li><a href="http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29" id="cite-3">ويكيبيديا - التغليف (البرمجة الكائنية التوجه</a><a href="http://ar.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29">)</a></li>
</ol>
<h2 id="أنظر_أيضا">أنظر أيضا</h2>
<ul>
<li dir="ltr">{{jsxref("Function.prototype.call()")}}</li>
<li dir="ltr">{{jsxref("Function.prototype.apply()")}}</li>
<li dir="ltr">{{jsxref("Object.create()")}}</li>
<li dir="ltr"><a dir="rtl" href="/en-US/docs/Web/JavaScript/Reference/Strict_mode">الوضع الصارم</a></li>
</ul>
|