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

ملحوظة: ينبغي تطبيق المعلومات الواردة من المنشور في الممارسة العملية بعناية فائقة وتحت إشراف زملاء أكثر خبرة.
هنا نتحدث عن ما هو مخفي في أعماق الأشياء ونناقش تعقيدات العمل معهم.
بعد إتقان هذه المادة ، ستعرف إجابات الأسئلة التالية:
- كيفية جعل خاصية كائن غير قابل للعزل؟
- ما هي الخصائص مع طرق الوصول وما هي ميزاتها؟
- كيفية جعل خاصية ثابتة أو خفية؟
- لماذا بعض الخصائص غير مرئية في حلقات
for-in
أو في نتائج الأسلوب Object.keys()
، وبعضها مرئي؟ - كيفية "حماية" كائن من التعديل؟
- كيفية فهم قطعة من التعليمات البرمجية مشابهة لما يلي:
obj.id = 5; console.log(obj.id)
أنواع خصائص الكائن
Storage خصائص تخزين البيانات
ربما تكون قد أنشأت كائنات لا حصر لها تشبه هذا:
const obj = { name: 'Arfat', id: 5 } obj.name
تسمى خصائص
id
الكائن
obj
بخصائص
obj
البيانات ، أو "خصائص البيانات". هذه خصائص مألوفة توجد باستمرار في شفرة JavaScript. ما أنواع الخصائص الأخرى التي يمكن أن تحتوي عليها الكائنات؟
with خصائص مع طرق الوصول
تُعرف هذه الخصائص أيضًا باسم getters و setters ، كما توجد أيضًا في لغات البرمجة الأخرى مثل C # أو Python. الخاصية مع Accessor Property هي مزيج من وظيفتين -
get
set
.
عند التصريح بهذه الخصائص ، بدلاً من استخدام بنية نوع
:
التقليدية ، يتم استخدام بناء الجملة التالي:
const accessorObj = { get name() { return 'Arfat'; } }; accessorObj.name;
ألق نظرة على كائن
dataObj
بالكائن
dataObj
. على ما يبدو ، الآن يظهرون نفس السلوك. عند وصف الكائن الأول ، استخدمنا الكلمة
get
، يليها إعلان الوظيفة. للوصول إلى خاصية مماثلة ، على الرغم من تمثيلها بواسطة دالة ، لا تحتاج إلى وضع أقواس بعد اسم الخاصية لاستدعاء هذه الوظيفة. أي ، تصميم مثل
accessorObj.name();
غير صحيح
عند محاولة الوصول إلى خاصية
accessorObj.name
، أي عند محاولة قراءتها ، يتم تنفيذ الوظيفة المقابلة وتصبح القيمة التي يتم إرجاعها إليها هي قيمة خاصية
name
.
تسمى وظائف
get
على getters ؛ فهي مسؤولة عن الحصول على القيم. إذا واصلنا مثالنا وحاولنا تغيير قيمة خاصية
name
كائن
accessorObj
، على سبيل المثال ، من خلال تشغيل الأمر
accessorObj.name = 'New Person';
، ثم اتضح أنه لن يحدث شيء. النقطة هنا هي أن وظيفة setter غير مرتبطة بمفتاح
name
. تتيح لك هذه الوظائف تخصيص ترتيب تعيين قيم جديدة لخصائص الكائنات ، ويتم تنظيم الوصول إليها باستخدام getters.
إليك ما يبدو عليه شكل إعلان كائن مع واضعي و واضع:
const accessorObj = { _name: 'Arfat', get name() { return this._name; }, set name(value) { this._name = value; } };
تتلقى وظيفة setter ما يحاولون تعيينه إلى خاصية الكائن كمعلمة. الآن يمكنك حفظ شيء في خاصية الكائن. في هذه الحالة ، نقوم بإنشاء خاصية "خاصة" لكائن
_name
. الحرف الأول من اسم مثل هذه الخاصية هو الشرطة السفلية ، وهي ليست سوى تلميح للمبرمج ، مما يشير إلى أن هذه الخاصية مخصصة لتلبية الاحتياجات الداخلية للكائن. علاوة على ذلك ، نحن نعمل معها عند الوصول إلى خاصية كائن
name
، والتي يتم تنظيم الوصول إليها من خلال getter و setter.
في نفس الوقت ، في دالة getter ، قبل إرجاع قيمة خاصية
_name
، يمكننا تعديلها.
إليك ما قد يبدو عليه:
const obj = { get name() { return this._name.toUpperCase(); }, set name(value) { this._name = value; }, get id() { return this._id.toString(2);
يحتوي هذا البرنامج ، بالمناسبة ، على إجابة على أحد الأسئلة التي تم طرحها في بداية المقال ، والتي تتعلق بتحليل غير مفهومة من النظرة الأولى للشفرة.
لماذا يحتاج شخص ما إلى خصائص مع أساليب الوصول إذا كنت تستطيع العمل بأمان مع الخصائص العادية؟ على سبيل المثال ، قد تكون هناك حاجة لتسجيل معلومات حول قراءات الممتلكات ، أو لتخزين محفوظات التغييرات في قيم الممتلكات. تمنحنا الخصائص التي لها طرق وصول جميع إمكانيات معالجة البيانات باستخدام وظائف وسمات البساطة في العمل مع الخصائص العادية. اقرأ المزيد عن استخدام هذه الخصائص
هنا .
كيف يميز JavaScript بين الخصائص العادية التي تخزن البيانات من الخصائص باستخدام طرق الوصول؟ اكتشف هذا.
واصفات خاصية الكائن
للوهلة الأولى ، قد يبدو أن هناك مراسلات مباشرة بين المفاتيح والقيم المخزنة في الكائنات. ومع ذلك ، هذا ليس صحيحا تماما.
▍ سمات الملكية
يرتبط كل مفتاح من عناصر الكائن بمجموعة من السمات التي تحدد خصائص القيمة المرتبطة بهذا المفتاح. يمكن أيضًا اعتبار هذه السمات بيانات وصفية تصف
:
زوج
:
.
يتم استخدام السمات لتعيين ووصف خصائص خصائص الكائنات. تسمى مجموعة سمات الخاصية واصفًا. هناك ستة سمات الملكية:
[[Value]]
[[Get]]
[[Set]]
[[Writable]]
[[Enumerable]]
[[Configurable]]
لماذا يتم تضمين أسماء سمات الخاصية في هذه القائمة في
[[]]
البناء؟ تشير الأقواس المزدوجة إلى أنها كيانات تستخدمها الآليات الداخلية للغة. لا يمكن لمبرمج JS الوصول إلى هذه الخصائص مباشرة. من أجل التأثير عليهم ، يتم استخدام الأساليب المناسبة.
النظر في الصورة التالية ، مأخوذة
من هنا ، والتي يمكنك أن ترى الكائن وسمات خصائصه.
كائن وسمات خصائصهكائن لدينا لديه مفاتيح 2 -
x
و
y
. علاوة على ذلك ، ترتبط مجموعة من السمات بكل منها.
كيف ، باستخدام جافا سكريبت ، للحصول على معلومات حول الكائن ، مماثلة لتلك التي تظهر في الشكل السابق؟ يمكنك استخدام
Object.getOwnPropertyDescriptor()
لهذا الغرض. يأخذ كائن واسم الخاصية الخاصة به ، ثم إرجاع كائن يحتوي على سمات هذه الخاصية. هنا مثال:
const object = { x: 5, y: 6 }; Object.getOwnPropertyDescriptor(object, 'x');
تجدر الإشارة إلى أن تكوين سمات خاصية معينة يعتمد على نوعه. لم يتم العثور على جميع السمات الست للممتلكات ذاتها.
- إذا كنا نتحدث عن الخصائص مع البيانات ، فلن يكون لها سوى السمات
[[Value]]
[[Writable]]
، [[Enumerable]]
[[Writable]]
، [[Enumerable]]
و [[Configurable]]
. - الخصائص التي لها طرق وصول ، بدلاً من السمات
[[Value]]
و [[Writable]]
، لها [[Writable]]
[[Get]]
و [[Set]]
.
▍ [[القيمة]]
تخزن هذه السمة ما يتم إرجاعه عند محاولة الحصول على قيمة خاصية كائن. هذا هو ، إذا استخدمنا في المثال السابق إنشاء
object.x
،
object.x
على ما يتم تخزينه في السمة
[[Value]]
. يحدث الشيء نفسه عند محاولة قراءة خصائص كائن باستخدام أقواس مربعة.
▍ [[Get]]
تخزن هذه السمة مرجعًا لوظيفة ، وهي خاصية getter. تسمى هذه الوظيفة بدون وسيطات عند محاولة قراءة قيمة الخاصية.
▍ [[مجموعة]]
هذا هو المكان الذي يتم فيه تحديد ارتباط الوظيفة المعلنة عند إنشاء خاصية setter. يتم استدعاؤها باستخدام وسيطة تمثل القيمة التي حاولوا تعيينها للخاصية ، أي ، يتم استدعاؤها خلال كل عملية من عمليات تخصيص خاصية بقيمة جديدة.
const obj = { set x(val) { console.log(val)
في هذا المثال ، يتم تمرير الجانب الأيمن من التعبير كوسيطة
val
لوظيفة setter.
إليك الكود الذي يوضح استخدام المستوطنين والأعراس.
▍ [[قابل للكتابة]]
تحتوي هذه السمة على قيمة منطقية. يشير إلى ما إذا كان يمكن الكتابة فوق قيمة الخاصية أم لا. إذا تم تخزين
false
هنا ، فستفشل محاولات تغيير قيمة الخاصية.
▍ [[معدود]]
يتم أيضًا تخزين القيمة المنطقية هنا. تتحكم هذه السمة في إصدار الخاصية
for-in
حلقات
for-in
. إذا تم ضبطه على "
true
، فسيكون من الممكن العمل مع العقار باستخدام هذه الدورات.
▍ [[شكلي]]
يتم تمثيل هذه السمة أيضًا بقيمة منطقية. هذا ما يحدث إذا تم تخزين
false
في:
- لا يمكن حذف العقار.
- لا يمكنك تحويل الخصائص التي تخزن البيانات إلى خصائص باستخدام طرق الوصول ، والعكس صحيح. محاولات إجراء مثل هذه التحولات لن تؤدي إلى شيء.
- لن يتم السماح بتغيير قيم الخاصية المميزة. بمعنى أن القيم الحالية للسمات
[[Enumerable]]
و [[Enumerable]]
[[Configurable]]
و [[Get]]
و [[Set]]
لن تتغير.
يعتمد تأثير تعيين هذه السمة على
false
أيضًا على نوع الخاصية. تعمل هذه السمة ، بالإضافة إلى التأثيرات المذكورة أعلاه على الخصائص ، عليها وما إلى ذلك:
- إذا كانت هذه خاصية تخزن البيانات ، فيمكن فقط تغيير السمة
[[Writable]]
من true
إلى false
. - حتى يتم ضبط السمة
[[Writable]]
على false
، يمكن تغيير السمة [[Value]]
. ولكن بعد أن يتم تعيين السمات [[Writable]]
و [[Configurable]]
على " false
، ستتحول الخاصية إلى غير قابلة للإنضغاط ، غير قابلة للتشكيل ، وغير قابلة للتغيير.
العمل مع الواصفات
الآن وقد أصبحنا على دراية بالسمات ، سنسأل أنفسنا كيف يمكننا التأثير عليها. يحتوي JavaScript على وظائف خاصة للتعامل مع واصفات الخصائص. دعنا نتحدث عنهم.
Object طريقة Object.getOwnPropertyDescriptor ()
لقد التقينا بالفعل هذه الطريقة. يؤدي أخذ كائن واسم ملكيته إلى إرجاع إما
undefined
أو كائن مع واصف خاصية.
▍ طريقة الكائن. تعريف المشروع ()
هذا هو أسلوب
Object
ثابت يسمح لك بإضافة خصائص إلى الكائنات أو تغيير الخصائص الموجودة. يستغرق الأمر ثلاث وسيطات - كائن ، واسم خاصية ، وكائن به واصف. هذه الطريقة تقوم بإرجاع كائن معدل. النظر في مثال:
const obj = {};
يمكن تشغيله في Node.js. تبين أن الكود كبير جدًا ، لكنه في الحقيقة بسيط للغاية. سنقوم بتحليلها ، مع التركيز على تعليقات النموذج
// #n
.
في الجزء
#1
نستخدم الدالة
defineProperty
،
defineProperty
كائن
obj
، واسم خاصية
id
، وكائن واصف يحتوي فقط على خاصية
value
، مما يشير إلى أنه سيتم كتابة
42
إلى السمة
[[Value]]
. تذكر أنه إذا لم تقم بتمرير قيم لسمات مثل
[[Enumerable]]
أو
[[Configurable]]
في هذا الكائن ، فسيتم تعيينها على "
false
افتراضيًا. في هذه الحالة ، يتم تعيين السمات
[[Writable]]
،
[[Enumerable]]
و
[[Configurable]]
لخاصية
id
على "
false
.
في المكان المحدد بالعلامة
#2
، نحاول عرض تمثيل سلسلة للكائن في وحدة التحكم. نظرًا لأن خاصية معرفها غير قابلة للتعداد ، فلن يتم عرضها. علاوة على ذلك ، توجد الخاصية ، مما يثبت نجاحها من خلال الأمر
#3
.
عند إنشاء كائن (الجزء
#4
) ، نحدد قائمة كاملة من السمات. على وجه الخصوص ، اضبط
[[Writable]]
على
false
.
باستخدام الأمرين
#5
ورقم
#7
نعرض قيمة خاصية
name
. لكن بينهما (الجزء
#6
) حاولنا تغيير هذه القيمة. لم تغير هذه العملية قيمة الخاصية لأن السمة
[[Writable]]
مضبوطة على
false
. نتيجة لذلك ، يخرج كلا الأمرين نفس الشيء إلى وحدة التحكم.
الأمر
#8
هو محاولة لإزالة خاصية
id
. تذكر أنه تم تعيين السمة
[[Configurable]]
على "
false
، مما يعني أنه لا يمكن حذفها. ثبت هذا من قبل الفريق
#9
.
يوضح الجزء
#10
استخدام الدالة
Object.defineProperties () . إنه يعمل بنفس وظيفة
defineProperty()
، لكنه يسمح ، في مكالمة واحدة ، بالتأثير على العديد من خصائص الكائن ، بينما يعمل
defineProperty()
مع خاصية واحدة فقط للكائن.
حماية الكائن
من وقت لآخر ، يحتاج المطور إلى حماية الكائنات من التداخل الخارجي. على سبيل المثال ، بالنظر إلى مرونة JavaScript ، من السهل جدًا تغيير خصائص كائن لا ينبغي تغييره. هناك ثلاث طرق رئيسية لحماية الكائنات.
Object طريقة Object.preventExtensions ()
يمنع الأسلوب
Object.preventExtensions()
توسيع الكائن ، أي إضافة خصائص جديدة إليه. يستغرق كائن ويجعله غير قابل للتوسيع. لاحظ أنه يمكنك إزالة الخصائص من مثل هذا الكائن. النظر في مثال:
const obj = { id: 42 }; Object.preventExtensions(obj); obj.name = 'Arfat'; console.log(obj);
لمعرفة ما إذا كان الكائن غير قابل للتوسيع ، يمكنك استخدام الأسلوب
Object.isExtensible()
. إذا تم إرجاع
true
، فيمكنك إضافة خصائص جديدة إلى الكائن.
▍ طريقة Object.seal ()
يبدو أن طريقة
seal()
إلى "ختم" الكائنات. هنا ما نتحدث عنه:
- يمنع استخدامه خصائص جديدة من إضافتها إلى الكائن (في هذا يشبه
Object.preventExtensions()
). - يجعل كافة الخصائص الموجودة لكائن غير قابلة للتكوين.
- يمكن تغيير قيم الخصائص الحالية ، إذا لم يتم تعيين السمة
[[Writable]]
على " false
.
نتيجة لذلك ، اتضح أن هذه الطريقة تمنع إضافة خصائص جديدة إلى الكائن وإزالة الخصائص الموجودة فيه.
النظر في مثال:
const obj = { id: 42 }; Object.seal(obj); delete obj.id
للتحقق مما إذا كان الكائن "مختومًا" أم لا ، يمكنك استخدام الأسلوب
Object.isSealed()
.
▍ طريقة Object.freeze ()
تتيح لك طريقة
freeze()
"تجميد" الكائنات وتزويدهم بأعلى مستوى ممكن من الحماية في JavaScript. إليك كيف تعمل:
- الأختام كائن باستخدام
Object.seal()
. - يحظر تمامًا تعديل أي من خصائص الكائن الموجودة.
- يحظر تعديل واصفات الخصائص.
هنا مثال:
const obj = { id: 42 }; Object.freeze(obj); delete obj.id
يمكنك التحقق من الكائن ما إذا كان "مجمداً" باستخدام الأسلوب
Object.isFrozen()
.
▍ نظرة عامة على الطرق المستخدمة لحماية الكائنات
من المهم ملاحظة أن الأساليب المذكورة أعلاه المستخدمة لحماية الكائنات تؤثر فقط على خصائصها التي ليست كائنات.
فيما يلي جدول ملخص للطرق المدروسة لحماية الكائنات ، والتي يتم أخذها
من هنا .
| إنشاء الممتلكات
| قراءة الممتلكات
| الملكية الكتابة
| إزالة الملكية
|
Object.freeze()
| - | +
| - | - |
Object.seal()
| - | +
| +
| - |
Object.preventExtensions()
| - | +
| +
| +
|
ملخص
بالنظر إلى عدد مرات استخدام الكائنات في JavaScript ، من المهم أن يعرف كل مطور كيف يتم ترتيبها. نأمل أن يكون ما تعلمته بقراءة هذه المادة مفيدًا لك. بالإضافة إلى ذلك ، أنت الآن تعرف إجابات الأسئلة المدرجة في بداية المقالة.
أعزائي القراء! كيف تحمي كائنات JavaScript؟