لنأخذ راحة صغيرة بعيدًا عن بنى البيانات ولنتحدّث عن طريقة المرور على عناصرها.
رأينا في الفصل السابق التوابِع map.keys()
وmap.values()
وmap.entries()
. هذه التوابِع عامّة وقد اتّفق معشر المطوّرين على استعمالها عند التعامل مع بنى البيانات. ولو أنشأنا بنية بيانات من الصفر بيدنا، فعلينا توفير "تنفيذ" تلك التوابِع أيضًا. هي أساسًا مدعومة لكلّ من:
-
الخرائط
Map
-
الأطقم
Set
-
المصفوفات
Array
كما وتدعم الكائنات العادية توابِع كتلك التوابِع باختلاف بسيط في صياغتها.
التوابِع keys وvalues وentries
هذه هي التوابِع المتاحة للتعامل مع الكائنات العادية:
-
Object.keys(obj)
-- يُعيد مصفوفة من المفاتيح. -
Object.values(obj)
-- يُعيد مصفوفة من القيم. -
Object.entries(obj)
-- يُعيد مصفوفة من أزواج[key, value]
.
لاحظ رجاءً الفروق بينها وبين الخارطة مثلًا:
الخارطة | الكائن | |
---|---|---|
صياغة الاستدعاء |
map.keys()
|
Object.keys(obj) لكن ليس obj.keys()
|
قيمة الإعادة | مُكرَّر | مصفوفة ”حقيقية“ |
أوّل فرق واضح جليّ: علينا استدعاء Object.keys(obj)
لا obj.keys()
. ولكن لماذا؟ السبب الأساس هو مرونة الاستعمال. لا تنسَ بأنّ الكائنات هي أساس كلّ بنية بيانات معقّدة في جافاسكربت. يحدث بأنّ لدينا كائن طوّرناه ليحمل بيانات data
محدّدة، وفيه التابِع data.values()
، ولكنّا نريد أيضًا استدعاء Object.values(data)
عليه.
الفرق الثاني هو أنّ التوابِع Object.*
تُعيد كائنات مصفوفات ”فعلية“ لا مُتعدَّدات فقط. يعزو ذلك لأسباب تاريخية بحتة. خُذ هذا المثال:
let user = { name: "John", age: 30 };
-
Object.keys(user) = ["name", "age"]
-
Object.values(user) = ["John", 30]
-
Object.entries(user) = [ ["name","John"], ["age",30] ]
وهذا مثال آخر عن كيف نستعمل Object.values
للمرور على قيم الخاصيات:
let user = { name: "John", age: 30 }; // نمرّ على القيم for (let value of Object.values(user)) { alert(value); // John ثمّ 30 }
تتجاهل هذه التوابِع الخاصيات الرمزية كما تتجاهل حلقة for..in
الخاصيات التي تستعمل Symbol(...)
مفاتيح لها، فهذه التوابِع أعلاه تتجاهلها أيضًا
غالبًا يكون هذا ما نريد، ولكن لو أردت المفاتيح الرمزية أيضًا، فعليك استعمال التابِع المنفصل Object.getOwnPropertySymbols إذ يُعيد مصفوفة بالمفاتيح الرمزية فقط. هناك أيضًا التابِع Reflect.ownKeys(obj) إذ يُعيد المفاتيح كلها.
تعديل محتوى الكائنات
ليس للكائنات تلك التوابِع المفيدة المُتاحة للعناصر (مثل map
وfilter
وغيرها). لو أردنا تطبيق هذه التوابِع على الكائنات فيجب أوّلًا استعمال Object.entries
وبعدها Object.fromEntries
:
-
استعمل
Object.entries(obj)
لتأخذ مصفوفة لها أزواج ”مفتاح/قيمة“ من الكائنobj
. -
استعمل توابِع المصفوفات على تلك المصفوفة (مثلًا
map
). -
استعمل
Object.fromEntries(array)
على المصفوفة الناتج لتُحوّلها ثانيةً إلى كائن.
إليك مثالًا لدينا كائنًا فيه تسعير البضائع، ونريد مضاعفتها (إذ ارتفع الدولار):
let prices = { banana: 1, orange: 2, meat: 4, }; let doublePrices = Object.fromEntries( // نحوّله إلى مصفوفة، ثمّ نستعمل الطقم، ثمّ يُعيد إلينا fromEntries الكائن المطلوب Object.entries(prices).map(([key, value]) => [key, value * 2]) ); alert(doublePrices.meat); // 8
ربّما تراه صعبًا أوّل وهلة، ولكن لا تقلق فسيصير أسهل أكثر متى ما بدأت استعمالها مرّة واثنتان وثلاث. يمكن أن نصنع سلسلة فعّالة من التعديلات بهذه الطريقة:
تمارين
مجموع الخاصيات
الأهمية: 5
أمامك كائن salaries
وفيه بعض الرواتب. اكتب دالة sumSalaries(salaries)
تُعيد مجموع كلّ الرواتب، باستعمال Object.values
وحلقة for..of
. لو كان الكائن فارغًا فيجب أن يكون الناتج صفرًا 0
.
مثال:
let salaries = { "John": 100, "Pete": 300, "Mary": 250 }; alert( sumSalaries(salaries) ); // 650
الحل
function sumSalaries(salaries) { let sum = 0; for (let salary of Object.values(salaries)) { sum += salary; } return sum; // 650 } let salaries = { "John": 100, "Pete": 300, "Mary": 250 }; alert( sumSalaries(salaries) ); // 650
أو يمكننا (لو أردنا) معرفة المجموع باستعمال Object.values
والتابِع reduce
:
// يمرّ reduce على مصفوفة من الرواتب، // ويجمعها مع بعضها ويُعيد الناتج function sumSalaries(salaries) { return Object.values(salaries).reduce((a, b) => a + b, 0) // 650 }
عدد الخاصيات
الأهمية: 5
اكتب دالة باسم count(obj)
تُعيد عدد الخاصيات داخل الكائن:
let user = { name: 'John', age: 30 }; alert( count(user) ); // 2
حاوِل أن تكون الشيفرة بأصغر ما أمكن.
ملاحظة: أهمِل الخاصيات الرمزية وعُدّ فقط تلك ”العادية“.
الحل
function count(obj) { return Object.keys(obj).length; }
ترجمة -وبتصرف- للفصل Object.keys, values, entries من كتاب The JavaScript language
اقرأ أيضًا
- المقال التالي: الإسناد بالتفكيك (Destructuring assignment)
- المقال السابق: النوع WeakMap والنوع WeakSet: الخرائط والأطقم ضعيفة الإشارة
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.