يستخدم JavaScript نموذج الوراثة النموذجي: كل كائن يرث الحقول (الخصائص) وطرق كائن النموذج الأولي.
لا توجد في JavaScript الفئات المستخدمة في Java أو Swift كقوالب أو مخططات لإنشاء كائنات. لا يوجد سوى كائنات في الوراثة النموذجية.
يمكن أن تحاكي الوراثة النموذجية النموذج الكلاسيكي لميراث الطبقة. للقيام بذلك ، قدم ES6 الكلمة الأساسية للفئة: السكر النحوي للوراثة النموذجية.
في هذه المقالة ، سوف نتعلم كيفية التعامل مع الفصول الدراسية: تحديد الفصول ، ومجالاتها وأساليبها الخاصة (الخاصة) والعامة (العامة) ، وإنشاء مثيلات.
1. التعريف: فئة الكلمة
تُستخدم الكلمة الأساسية للفصل لتحديد فئة:
class User {
//
}
هذا النحو يسمى إعلان الفئة.
قد لا يكون للفصل اسم. باستخدام تعبير فئة ، يمكنك تعيين فئة إلى متغير:
const UserClass = class {
//
}
يمكن تصدير الفئات كوحدات نمطية. فيما يلي مثال على التصدير الافتراضي:
export default class User {
//
}
وإليك مثال على تصدير مسمى:
export class User {
//
}
تستخدم الفئات لإنشاء حالات. المثيل هو كائن يحتوي على البيانات والمنطق الخاص بالفئة.
يتم إنشاء المثيلات باستخدام عامل التشغيل new: example = new Class ().
فيما يلي كيفية إنشاء مثيل لفئة المستخدم:
const myUser = new User()
2. التهيئة: المُنشئ ()
المُنشئ (param1، param2، ...) هي طريقة خاصة داخل فئة تقوم بتهيئة مثيل. هذا هو المكان الذي يتم فيه تعيين القيم الأولية لحقول المثيل وتكوينها.
في المثال التالي ، يعيّن المُنشئ القيمة الأولية لحقل الاسم:
class User {
constructor(name) {
this.name = name
}
}
يأخذ المُنشئ معلمة واحدة ، الاسم ، والتي تُستخدم لتعيين القيمة الأولية للحقل this.name.
هذا في المنشئ يشير إلى المثيل الذي يتم إنشاؤه.
تصبح الوسيطة المستخدمة لإنشاء مثيل للفئة معلمة لمنشئها:
class User {
constructor(name) {
name //
this.name = name
}
}
const user = new User('')
قيمة معلمة الاسم داخل المُنشئ هي "Pechorin".
إذا لم تحدد المُنشئ الخاص بك ، فسيتم إنشاء مُنشئ قياسي ، وهو دالة فارغة لا تؤثر على المثيل.
3. الحقول
حقول الفئة هي متغيرات تحتوي على معلومات محددة. يمكن تقسيم الحقول إلى مجموعتين:
- حقول مثيل الفئة
- مجالات الفصل نفسه (ثابت)
تحتوي الحقول أيضًا على مستويين للوصول:
- عام (عام): الحقول متاحة داخل الفصل وفي الأمثلة
- خاص (خاص): الحقول متاحة فقط داخل الفصل
3.1. المجالات العامة لمثيلات الفصل
class User {
constructor(name) {
this.name = name
}
}
ينشئ التعبير this.name = name اسم حقل مثيل ويعين قيمة أولية له.
يمكن الوصول إلى هذا الحقل باستخدام موصّل الخاصية:
const user = new User('')
user.name //
في هذه الحالة ، يكون الاسم حقلاً عامًا لأنه يمكن الوصول إليه خارج فئة المستخدم.
عند إنشاء الحقول بشكل ضمني داخل المُنشئ ، من الصعب الحصول على قائمة بجميع الحقول. لهذا ، يجب استرداد الحقول من المنشئ.
أفضل طريقة هي تحديد مجالات الفصل بشكل صريح. لا يهم ما يفعله المُنشئ ، فالمثيل له دائمًا نفس مجموعة الحقول. يتيح لك
اقتراح إنشاء حقول الفصل تحديد الحقول داخل الفصل. بالإضافة إلى ذلك ، يمكنك هنا تعيين قيم أولية للحقول:
class SomeClass {
field1
field2 = ' '
// ...
}
دعنا نغير كود فئة المستخدم عن طريق تحديد حقل الاسم العام فيه:
class User {
name
constructor(name) {
this.name = name
}
}
const user = new User('')
user.name //
هذه الحقول العامة وصفية للغاية ، وتسمح لك نظرة سريعة على الفصل بفهم بنية بياناته.
علاوة على ذلك ، يمكن تهيئة حقل الفصل في وقت التعريف:
class User {
name = ''
constructor() {
//
}
}
const user = new User()
user.name //
لا توجد قيود على الوصول إلى الحقول المفتوحة وتغييرها. يمكنك قراءة هذه الحقول وتعيين قيم لها في المنشئ والأساليب وخارج الفصل الدراسي.
3.2 المجالات الخاصة لمثيلات الفصل
يسمح لك التغليف بإخفاء تفاصيل التنفيذ الداخلي للفصل الدراسي. يعتمد كل من يستخدم الفئة المغلفة على الواجهة العامة دون الخوض في تفاصيل تنفيذ الفصل.
يسهل تحديث هذه الفئات عند تغيير تفاصيل التنفيذ.
طريقة جيدة لإخفاء التفاصيل هي استخدام الحقول الخاصة. يمكن قراءة هذه الحقول وتغييرها فقط داخل الفصل الذي ينتمون إليه. الحقول الخاصة غير متوفرة خارج الفصل.
لجعل حقل ما خاصًا ، اسبق اسمه بالرمز # ، على سبيل المثال ، #myPrivateField. عند الإشارة إلى مثل هذا الحقل ، يجب دائمًا استخدام البادئة المحددة.
لنجعل حقل الاسم خاصًا:
class User {
#name
constructor(name) {
this.#name = name
}
getName() {
return this.#name
}
}
const user = new User('')
user.getName() //
user.#name // SyntaxError
#name هو حقل خاص. لا يمكن الوصول إليه إلا داخل فئة المستخدم. تقوم طريقة getName () بهذا.
ومع ذلك ، ستؤدي محاولة الوصول إلى #name خارج فئة المستخدم إلى ظهور خطأ في بناء الجملة: خطأ في بناء الجملة: يجب التصريح عن الحقل الخاص '#name' في فئة التضمين.
3.3 المجالات العامة الثابتة
في الفصل ، يمكنك تحديد الحقول التي تنتمي إلى الفئة نفسها: الحقول الثابتة. يتم استخدام هذه الحقول لإنشاء ثوابت تخزن المعلومات التي يحتاجها الفصل.
لإنشاء حقول ثابتة ، استخدم الكلمة الأساسية الثابتة قبل اسم الحقل: static myStaticField.
دعنا نضيف حقل نوع جديد لتحديد نوع المستخدم: مسؤول أو عادي. الحقول الثابتة TYPE_ADMIN و TYPE_REGULAR هي ثوابت لكل نوع من أنواع المستخدمين:
class User {
static TYPE_ADMIN = 'admin'
static TYPE_REGULAR = 'regular'
name
type
constructor(name, type) {
this.name = name
this.type = type
}
}
const admin = new User(' ', User.TYPE_ADMIN)
admin.type === User.TYPE_ADMIN // true
للوصول إلى الحقول الثابتة ، استخدم اسم الفئة واسم الخاصية: User.TYPE_ADMIN و User.TYPE_REGULAR.
3.4. الحقول الثابتة الخاصة
أحيانًا تكون الحقول الثابتة جزءًا من التنفيذ الداخلي للفصل الدراسي. لتغليف هذه الحقول ، يمكنك جعلها خاصة.
للقيام بذلك ، ابدأ اسم الحقل بـ #: static #myPrivateStaticFiled.
لنفترض أننا نريد تحديد عدد مثيلات فئة المستخدم. يمكن إنشاء حقول ثابتة خاصة لإخفاء المعلومات حول عدد المثيلات:
class User {
static #MAX_INSTANCES = 2
static #instances = 0
}
name
constructor(name) {
User.#instances++
if (User.#instances > User.#MAX_INSTANCES) {
throw new Error(' User')
}
this.name = name
}
new User('')
new User('')
new User('') // User
الحقل الثابت User. # MAX_INSTANCES يحدد العدد المسموح به من المثيلات ، و User. # مثيلات تحدد عدد المثيلات التي تم إنشاؤها.
هذه الحقول الثابتة الخاصة متاحة فقط داخل فئة المستخدم. لا شيء من العالم الخارجي يمكنه التأثير على القيود: هذه إحدى مزايا التغليف.
تقريبا. الممر: إذا حددت عدد المثيلات بواحد ، فستحصل على تنفيذ مثير للاهتمام لنمط تصميم Singleton.
4. الطرق
تحتوي الحقول على بيانات. يتم توفير القدرة على تغيير البيانات من خلال وظائف خاصة تشكل جزءًا من الفئة: الطرق.
يدعم JavaScript كلاً من طرق المثيل والطرق الثابتة.
4.1 طرق المثيل
يمكن لطرق مثيل فئة ما تعديل بياناتها. يمكن أن تستدعي طرق المثيل طرق مثيل أخرى بالإضافة إلى طرق ثابتة.
على سبيل المثال ، دعنا نحدد طريقة getName () التي تُرجع اسم المستخدم:
class User {
name = ''
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
const user = new User('')
user.getName() //
في طريقة الفئة ، وكذلك في المنشئ ، يشير هذا إلى المثيل الذي يتم إنشاؤه. استخدم هذا للحصول على بيانات المثيل: this.field ، أو لاستدعاء التوابع: this.method ().
دعنا نضيف طريقة جديدة nameContains (str) تأخذ وسيطة واحدة وتستدعي طريقة أخرى:
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
nameContains(str) {
return this.getName().includes(str)
}
}
const user = new User('')
user.nameContains('') // true
user.nameContains('') // false
nameContains (str) هي طريقة لفئة المستخدم تأخذ وسيطة واحدة. تستدعي طريقة مثيل أخرى getName () للحصول على اسم المستخدم.
يمكن أن تكون الطريقة خاصة أيضًا. لجعل الطريقة خاصة ، استخدم البادئة #.
لنجعل طريقة getName () خاصة:
class User {
#name
constructor(name) {
this.#name = name
}
#getName() {
return this.#name
}
nameContains(str) {
return this.#getName().includes(str)
}
}
const user = new User('')
user.nameContains('') // true
user.nameContains('') // false
user.#getName // SyntaxError
#getName () هي طريقة خاصة. داخل طريقة nameContains (str) ، نسميها هكذا # GetName ().
كونها خاصة ، لا يمكن استدعاء طريقة #getName () خارج فئة المستخدم.
4.2 حاصلون وخطابات
الحاصلون والمحددون هم موصّلون أو خصائص محسوبة هذه طرق تحاكي الحقول ، ولكنها تسمح لك بقراءة البيانات وكتابتها.
يتم استخدام أدوات التسجيل لتلقي البيانات ، ويتم استخدام المحددات لتعديلها.
لمنع تعيين سلسلة فارغة لحقل الاسم ، قم بلف الحقل #nameValue الخاص في getter و setter:
class User {
#nameValue
constructor(name) {
this.name = name
}
get name() {
return this.#nameValue
}
set name(name) {
if (name === '') {
throw new Error(' ')
}
this.#nameValue = name
}
}
const user = new User('')
user.name // ,
user.name = '' //
user.name = '' //
4.3 طرق ثابتة
الطرق الثابتة هي وظائف تنتمي إلى الفئة نفسها. إنهم يعرّفون منطق الفصل وليس أمثلةه.
لإنشاء طريقة ثابتة ، استخدم الكلمة الأساسية الثابتة أمام اسم الطريقة: static myStaticMethod ().
عند العمل بالطرق الثابتة ، هناك قاعدتان بسيطتان يجب وضعها في الاعتبار:
- الأسلوب الثابت لديه حق الوصول إلى الحقول الثابتة
- ليس لديه حق الوصول إلى حقول المثال
لنقم بإنشاء طريقة ثابتة للتحقق من إنشاء مستخدم بالاسم المحدد:
class User {
static #takenNames = []
static isNameTaken(name) {
return User.#takenNames.includes(name)
}
name = ''
constructor(name) {
this.name = name
User.#takenNames.push(name)
}
}
const user = new User('')
User.isNameTaken('') // true
User.isNameTaken('') // false
isNameTaken () هي طريقة ثابتة تستخدم الحقل الثابت الخاص User. # takeNames لتحديد الأسماء التي تم استخدامها.
يمكن أيضًا أن تكون الأساليب الثابتة خاصة: static #myPrivateStaticMethod (). لا يمكن استدعاء مثل هذه الأساليب إلا داخل الفصل.
5. الميراث: يمتد
تدعم الفئات في JavaScript الوراثة باستخدام الكلمة الأساسية الممتدة.
في التعبير ، تقوم الفئة Child بتوسيع الأصل {} ، وترث الفئة الفرعية المنشئات والحقول والأساليب من الأصل.
دعنا ننشئ فئة فرعية ContentWriter التي توسع المستخدم الأصلي للفئة:
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class ContentWriter extends User {
posts = []
}
const writer = new ContentWriter('')
writer.name //
writer.getName() //
writer.posts // []
يرث ContentWriter من المستخدم المُنشئ وطريقة getName () وحقل الاسم. يحدد ContentWriter نفسه حقل منشورات جديد.
لاحظ أن الحقول الخاصة والأساليب الخاصة بالفئة الأصلية لا يتم توارثها بواسطة الفئات الفرعية.
5.1 المُنشئ الأصلي: super () في المُنشئ ()
من أجل استدعاء مُنشئ الفئة الأصل في الفصل الفرعي ، استخدم وظيفة super () الخاصة المتاحة في مُنشئ الفئة الفرعية.
دع مُنشئ ContentWriter يستدعي المنشئ الأصلي ويهيئ حقل المشاركات:
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class ContentWriter extends User {
posts = []
constructor(name, posts) {
super(name)
this.posts = posts
}
}
const writer = new ContentWriter('', [' '])
writer.name //
writer.posts // [' ']
super (name) في فئة فرعية ContentWriter يستدعي مُنشئ الفئة الأصل User.
لاحظ أنه يتم استدعاء super () في الباني الفرعي قبل استخدام هذه الكلمة الأساسية. استدعاء super () "يربط" المنشئ الأصل بالمثيل.
class Child extends Parent {
constructor(value1, value2) {
// !
this.prop2 = value2
super(value1)
}
}
5.2. المثال الأصلي: طرق فائقة
من أجل الوصول إلى طريقة الوالدين داخل فصل دراسي ، استخدم الاختزال السوبر الخاص:
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class ContentWriter extends User {
posts = []
constructor(name, posts) {
super(name)
this.posts = posts
}
getName() {
const name = super.getName()
if (name === '') {
return ''
}
return name
}
}
const writer = new ContentWriter('', [' '])
writer.getName() //
يستدعي getName () الخاص بفئة ContentWriter الفرعية طريقة getName () الخاصة بفئة المستخدم الأصل.
وهذا ما يسمى أسلوب التجاوز.
لاحظ أنه يمكن استخدام super للطرق الثابتة للفئة الأم أيضًا.
6. فحص نوع الكائن: exampleof
يحدد مثيل الكائن من تعبير الفئة ما إذا كان الكائن مثيلًا للفئة المحددة.
لنفكر في مثال:
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
const user = new User('')
const obj = {}
user instanceof User // true
obj instanceof User // false
إن مثيل عامل التشغيل متعدد الأشكال: فهو يفحص سلسلة الفئة بأكملها.
class User {
name
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class ContentWriter extends User {
posts = []
constructor(name, posts) {
super(name)
this.posts = posts
}
}
const writer = new ContentWriter('', [' '])
writer instanceof ContentWriter // true
writer instanceof User // true
ماذا لو احتجنا إلى تحديد فئة مثيل معينة؟ يمكن استخدام خاصية المُنشئ لهذا:
writer.constructor === ContentWriter // true
writer.constructor === User // false
//
writer.__proto__ === ContentWriter.prototype // true
writer.__proto__ === User.prototype // false
7. فئات ونماذج
يجب أن يقال أن بناء الجملة هو تجريد لطيف على الميراث النموذجي. لا تحتاج إلى الرجوع إلى النماذج الأولية لاستخدام الفئات.
ومع ذلك ، فإن الطبقات هي مجرد بنية فوقية للوراثة النموذجية. أي فئة هي وظيفة تنشئ مثيلًا عند استدعاء مُنشئ.
المثالان التاليان متطابقان.
الطبقات:
class User {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
const user = new User('')
user.getName() //
user instanceof User // true
النماذج الأولية:
function User(name) {
this.name = name
}
User.prototype.getName = function () {
return this.name
}
const user = new User('')
user.getName() //
user instanceof User // true
لذلك ، يتطلب فهم الطبقات معرفة جيدة بالميراث النموذجي.
8. توافر القدرات الطبقية
يتم تقسيم قدرات الفئة المقدمة في هذه المقالة بين مواصفات ومقترحات ES6 في المرحلة الثالثة من الدراسة:
- حقول المثيل العامة والخاصة
- طرق المثيل الخاص و Accessors
- المجالات الثابتة العامة والخاصة والأساليب الثابتة الخاصة
- مواصفات ES6
تقريبا. لكل: وفقًا لـ Can I Use ، يبلغ دعم حقول الفصل الخاص حاليًا 68 ٪.
9. الخلاصة
تُستخدم الفئات في JavaScript لتهيئة المثيلات باستخدام المُنشئ ، وتحديد حقولها وطرقها. يمكن استخدام الكلمة الأساسية الثابتة لتحديد الحقول وطرق الفصل نفسه.
يتم تنفيذ الوراثة باستخدام الكلمة الأساسية الموسعة. تتيح لك الكلمة الرئيسية الفائقة الوصول إلى فئة الوالدين من الطفل.
من أجل الاستفادة من التغليف ، أي إخفاء تفاصيل التنفيذ الداخلي ، وجعل الحقول والأساليب خاصة. يجب أن تبدأ أسماء هذه الحقول والأساليب بالرمز #.
الفئات موجودة في كل مكان في JavaScript الحديث.
آمل أن تكون هذه المقالة مفيدة لك. شكرآ لك على أهتمامك.