التغليف
مفهوم التغليف
التغليف (Encapsulation) عبارة عن أسلوب يمكن اتباعه لإخفاء خصائص الكلاس (Class Attributes) بهدف حمايتها من أي تعديلات خارجية، فيكون التعامل معها ممكن فقط من خلال دوال أخرى موجودة في الكلاس.
في هذا الدرس ستتعرف على أهمية التغليف و جميع الطرق التي يمكنك اتباعها لتطبيق هذا الأسلوب.
أهمية التغليف
حتى تتضح لك أهمية التغليف، سنسلط الضوء على المشاكل التي قد تحدث في حال لم يتم تغليف خصائص الكلاس.
في المثال التالي، قمنا بتعريف كلاس إسمه
name يفترض أن تحتوي نص يمثل الإسم.job يفترض أن تحتوي على نص يمثل إسم المهنة.age يفترض أن تحتوي على رقم يمثل العمر.
بعدها قمنا بإنشاء كائن من هذا الكلاس مع إعطاء قيم لجميع خصائصه و بدون مراعاة أنواع القيم التي يجب وضعها فيها.
مثال
<!DOCTYPE html>
<html>
<body>
<script>
// Person هنا قمنا بتعريف كلاس إسمه
class Person {
name;
job;
age;
}
// p إسمه Person هنا قمنا بإنشاء كائن من الكلاس
p = new Person();
// p هنا قمنا بإعطاء قيم لجميع خصائص الكائن
p.name = true;
p.job = false;
p.age = '20';
// p هنا قمنا بطباعة جميع قيم خصائص الكائن
document.write('Name: ' + p.name + '<br>');
document.write('Job: ' + p.job + '<br>');
document.write('Age: ' + p.age + '<br>');
</script>
</body>
</html>
لاحظ أنه إذا لم يتم تغليف الخصائص فإنه يمكن وضع قيم من أي نوع كان فيها. هذا الأمر قد يسبب مشاكل كبيرة إذا كان الكلاس يحتوي على دوال مبنية على قيم هذه الخصائص لأنه لا يمكن توقع نوع و حدود القيم الموجودة فيها.
طرق تطبيق التغليف
إفتراضياً، الخصائص التي يتم وضعها في الكلاس تكون عامة ( Public ) مما يعني أنه بإمكان أي كائن يتم إنشاؤه من الكلاس أن يصل إليها بشكل مباشر سواء كان الهدف الحصول على قيمتها أو تحديثها.
في حال أردت إخفاء خصائص كلاس بحيث لا يكون للكائن الذي يتم إنشاؤه منه القدرة على الوصول بشكل مباشر لها فإنه يجب جعلها خاصة ( Private ) و هذا الأمر يتم من خلال وضع الرمز
من بعدها، يجب أن توفير دوال عامة في الكلاس نفسه يمكن من خلالها الحصول على قيم الخصائص و دوال يمكن من خلالها تعيين أو تحديث قيمها.
إبتداءاً من الإصدار ES12 أصبح بالإمكان استخدام الرمز
دوال Setter و Getter
الدوال التي يتم تجهيزها للتعامل مع خصائص الكلاس المخفية يتم تسميتها على النحو التالي:
- إذا كانت ستستعمل للحصول على قيم الخصائص فإنه يتم جعلها تبدأ بالكلمة get و يليها إسم الخاصية، مثل الدالة
getName() . - إذا كانت ستستعمل لتعيين قيم للخصائص فإنه يتم جعلها تبدأ بالكلمة set و يليها إسم الخاصية، مثل الدالة
setName() .
في المثال التالي قمنا بجعل خصائص الكلاس مخفية و أضفنا دوال يمكن من خلالها التعامل معها.
مثال
<!DOCTYPE html>
<html>
<body>
<script>
// Person هنا قمنا بتعريف كلاس إسمه
class Person {
#name;
#job;
#age;
// #name هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
getName() {
return this.#name;
}
// #name هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
setName(name) {
this.#name = name;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
getJob() {
return this.#job;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
setJob(job) {
this.#job = job;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
getAge() {
return this.#age;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
setAge(age) {
this.#age = age;
}
}
// p إسمه Person هنا قمنا بإنشاء كائن من الكلاس
p = new Person();
// p هنا قمنا بإعطاء قيم لجميع خصائص الكائن
p.setName('Ahmed');
p.setJob('Full stack developer');
p.setAge(29);
// p هنا قمنا بطباعة جميع قيم خصائص الكائن
document.write('Name: ' + p.getName() + '<br>');
document.write('Job: ' + p.getJob() + '<br>');
document.write('Age: ' + p.getAge() + '<br>');
</script>
</body>
</html>
الدوال العامة التي يتم وضعها في الكلاس بهدف الوصول لخصائصه يمكن من خلالها أن يتم فحص القيم التي سيتم تخزينها في الخصائص و يمكن أيضاً تحديد كيف سيتم إرجاع القيم.
الكلمات المفتاحية get و set
إبتداءاً من الإصدار ES6 أصبح بالإمكان استخدام الكلمات المفتاحية
هنا عندما يرى مترجم جافاسكربت أنك مررت قيمة للدالة فإنه سيعلم أنك تريد استدعاء الدالة التي تقوم بتعيين قيمة للخاصية، أما إذا وجدك قمت باستدعاء الدالة و لم تمرر لها قيمة فإنه سيفهم أنك ترد استدعاء الدالة التي ترجع قيمة الخاصية.
في المثال التالي قمنا بجعل خصائص الكلاس مخفية و أضفنا دوال يمكن من خلالها التعامل معها.
مثال
<!DOCTYPE html>
<html>
<body>
<script>
// Person هنا قمنا بتعريف كلاس إسمه
class Person {
#name;
#job;
#age;
// #name هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get name() {
return this.#name;
}
// #name هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set name(name) {
this.#name = name;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get job() {
return this.#job;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set job(job) {
this.#job = job;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get age() {
return this.#age;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set age(age) {
this.#age = age;
}
}
// p إسمه Person هنا قمنا بإنشاء كائن من الكلاس
p = new Person();
// p هنا قمنا بإعطاء قيم لجميع خصائص الكائن
p.name = 'Ahmed';
p.job = 'Full stack developer';
p.age = 29;
// p هنا قمنا بطباعة جميع قيم خصائص الكائن
document.write('Name: ' + p.name + '<br>');
document.write('Job: ' + p.job + '<br>');
document.write('Age: ' + p.age + '<br>');
</script>
</body>
</html>
في المثال السابق قد يبدو لك أننا نتعامل مع خصائص الكائن المخفية بشكل مباشر و لكننا فعلياً نتعامل مع الدوال
الإستفادة من عملية التغليف
بدايةً، التغليف هو أسلوب ممتاز و متعارف عليه في ترتيب و تنظيم الكود و هذا الأمر يساعد على استخدامه و صيانته و مشاركته مع الغير.
الآن لو أردت معرفة كيف يمكن من خلال التغليف أن يتم فحص القيم قبل تخزينها و كيف يمكن أيضاُ أن يتم جلبها بالطريقة التي نريدها عند طلبها فهذا الأمر يتم من خلال تعديل الدوال العامة التي يمكن من خلالها الوصول للخصائص.
في المثال التالي جعلنا الخاصية
ملاحظة: بذات الطريقة التي اتبعناها يمكنك التعديل على الدوال التابعة للخصائص الأخرى الموضوعة في الكلاس.
مثال
<!DOCTYPE html>
<html>
<body>
<script>
// Person هنا قمنا بتعريف كلاس إسمه
class Person {
#name;
#job;
#age;
// #name هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get name() {
return this.#name;
}
// #name هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set name(name) {
this.#name = name;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get job() {
return this.#job;
}
// #job هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set job(job) {
this.#job = job;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها الحصول على قيمة الخاصية
get age() {
return this.#age;
}
// #age هنا قمنا بتجهيز دالة يمكن من خلالها تعيين قيمة الخاصية
set age(age) {
this.#age = age;
}
}
// p إسمه Person هنا قمنا بإنشاء كائن من الكلاس
p = new Person();
// p هنا قمنا بإعطاء قيم لجميع خصائص الكائن
p.name = 'Ahmed';
p.job = 'Full stack developer';
p.age = 29;
// p هنا قمنا بطباعة جميع قيم خصائص الكائن
document.write('Name: ' + p.name + '<br>');
document.write('Job: ' + p.job + '<br>');
document.write('Age: ' + p.age + '<br>');
</script>
</body>
</html>
الأمر
إذا أردت أن يتم إظهار الخطأ في الصفحة يمكنك استخدام الدالة