صفوف

طرحت ES6 مفهوم "الفئات" في JavaScript، الذي يختلف عن الفئات في لغات البرمجة الأخرى. هنا، الفئات هي دوال خاصة تعمل كقوالب لإنشاء كائنات تحتوي بالفعل على بيانات وخصائص مرتبطة بتلك البيانات والطرق المتعلقة بمعالجة تلك البيانات. تُسمى هذه الكائنات والخصائص والطرق إجمالاً "أعضاء" الفئة.

لتحديد فئة، استخدِم الكلمة الرئيسية class. باتباع أفضل الممارسات والاصطلاح الذي وضعته دوال الإنشاء المضمنة في JavaScript، ابدأ أي معرّف لفئة بحرف كبير:

class MyClass {}

تهدف الفئات إلى توفير طرق أكثر سهولة للعمل باستخدام الميزات المتقدمة للنماذج الأولية ودوال الدالة الإنشائية:

class MyClass {}

typeof MyClass;
> "function"

يُشار إلى هذه الصفوف أحيانًا باسم "السكر النحوي"، وذلك لأنه تمت إضافة الدروس إليها لتسهيل العمل باستخدام ميزات JavaScript المتقدّمة. ومع ذلك، لا تقدّم الفصول سوى اختصارًا مفيدًا للتعامل مع اكتساب النماذج الأولية. أدى تقديم بناء جملة الفئة إلى خلق فرص لمعالجة مشكلات التصميم الطويلة في JavaScript دون إدخال مشكلات التوافق مع الأنظمة القديمة. كمثال واحد، يتم دائمًا تقييم جميع الرموز البرمجية داخل النص الأساسي للفئة باستخدام الوضع المتشدد.

لإنشاء مثيل لفئة معيّنة، استخدِم عامل التشغيل new.

class MyClass {}

const myClassInstance = new MyClass();

myClassInstance;
> Object { }

الدوال المحددة داخل نصّ فئة معيّنة كطرق لكل مثيل من هذه الفئة.

class MyClass {
    classMethod() {
        console.log( "My class method." );
    }
}

const myClassInstance = new MyClass();

myClassInstance.classMethod();
> "My class method."

تصبح الطريقة المحددة داخل الفئة طريقة على النموذج الأولي للمثيل الناتج. نظرًا لطبيعة سلسلة النموذج الأولي، يمكنك استدعاء هذه الطرق مباشرةً على الكائن الناتج:

class MyClass {
  classMethod() {
    console.log( "My class method." );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { }
    <prototype>: Object { … }
        classMethod: function classMethod()
        constructor: class MyClass { constructor(myPassedValue) }
        <prototype>: Object { … }

myClassInstance.classMethod();
> "My class method."

يستدعي إنشاء مثيل لفئة طريقة constructor() خاصة تنفّذ أي "إعداد" لازم للمثيل الذي تم إنشاؤه حديثًا وإعداد أي خصائص مرتبطة به. تكون أي وسيطات يتم تمريرها إلى الفئة عند إنشاء المثيل متاحة لطريقة constructor():

class MyClass {
  constructor( myPassedValue ) {
    console.log( myPassedValue );
  }
}

const myClassInstance = new MyClass( "A string." );
> "A string."

في نصّ الفئة، تشير قيمة this إلى المثيل نفسه، مع إظهار أي خصائص معرّفة في this كخصائص لكل مثيل من هذه الفئة:

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProperty = myPassedValue;
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { instanceProperty: "A string." }

وتتوفر هذه الخصائص أيضًا لجميع الطرق ضمن نص الفئة:

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProp = myPassedValue;
  }
  myMethod() {
    console.log( this.instanceProp );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance.myMethod();
> "A string."

إذا لم تحدّد constructor() للفئة، سيفترض محرّك JavaScript أنّ constructor "تلقائي" فارغ. يمكن لكل فئة أن تحتوي على طريقة خاصة واحدة فقط باسم constructor():

class MyClass {
  constructor() {}
  constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor

يمكنك تعريف فئة باستخدام تعريف الفئة أو تعبير الفئة. الأمثلة السابقة كانت جميعها تعريفات الفئة، والتي تتطلب استدعاء الأسماء باستخدام new. يمكن تسمية تعبيرات الفئة أو تركها بدون اسم لإنشاء فئة "مجهولة".

let ClassExpression = class {
    constructor() {}
};

ClassExpression;
> class  {}

شيء واحد يمكنك استخدام تعبيرات فئة مجهولة المصدر من أجله هو الدوال التي تنشئ فئات "سريعة":

function classMaker() {
  return class {
    constructor() {}
  };
}

let MyVariable = classMaker();

MyVariable;
> class  {}

يؤدي إعادة تعريف فئة باستخدام تعريف فئة إلى حدوث خطأ في البنية:


class MyClass {
    constructor( ) {
        console.log( "My class." );
    }
};

class MyClass {
    constructor() {
        console.log( "My new class." );
    }
};
> Uncaught SyntaxError: redeclaration of class MyClass

ومع ذلك، تتيح لك تعبيرات الفئة إعادة تعريف فئة:

let ClassExpression = class MyClass { };

ClassExpression = class MyOtherClass {
    constructor( myString ) {
        this.myProp = myString;
    }
};

new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}

لا يمكنك استدعاء تعبير فئة مُسمّى حسب الاسم بالطريقة التي يمكنك بها تعريف تعريف الفئة. ومع ذلك، يتوفّر الاسم المعيّن لتعبير الفئة كخاصية للمثيل الذي تم إنشاؤه، وغالبًا ما يكون ذلك لتسهيل تصحيح الأخطاء:

let MyVariable = class MyClass {};

MyClass;
> Uncaught ReferenceError: MyClass is not defined

MyVariable;
> class MyClass {}

MyVariable.name;
> "MyClass"

عند إعداد متغيّر باستخدام تعبير فئة، يتم اتّباع قواعد الرفع لذلك المتغيّر على النحو المتوقّع. تتّبع نماذج بيانات الفئة قواعد "المنطقة الثابتة المؤقتة" نفسها المتّبعة في let وconst، وتتصرف كما لو لم يتم رفعها إلى أعلى نطاقها الحالي، أي أنّ استدعاء فئة قبل تعريف الفئة يؤدي إلى حدوث خطأ:

{
    let myVar = new MyClass( "Property string." );

    class MyClass {
        myProp;

        constructor( myString ) {
            this.myProp = myString;
        }
    };
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization

التحقق من فهمك

أي مما يلي يحدد الفئة بشكل صحيح؟

class MyClass {}
myClass = class {}
new class()

كم عدد طرق constructor() التي يمكن أن يتضمّنها الصف؟

واحد
لا ينطبق
غير محدودة