٢٠ مارس ٢٠٢١

مفاتيح الكائنات وقيمها ومدخلاتها

لنأخذ راحة صغيرة بعيدًا عن بنى البيانات ولنتحدّث عن طريقة المرور على عناصرها.

رأينا في الفصل السابق التوابِع map.keys()‎ و map.values()و map.entries(). هذه التوابِع عامّة وقد اتّفق معشر المطوّرين على استعمالها عند التعامل مع بنى البيانات. ولو أنشأنا بنية بيانات من الصفر بيدنا، فعلينا توفير “تنفيذ” تلك التوابِع أيضًا. هي أساسًا مدعومة لكلّ من:

  • Map الخرائط
  • Set الأطقم
  • Array المصفوفات

كما وتدعم الكائنات العادية توابِع كتلك التوابِع باختلاف بسيط في صياغتها.

التوابِع keys وvalues وentries

هذه هي التوابِع المتاحة للتعامل مع الكائنات العادية:

لاحظ رجاءً الفروق بينها وبين الخارطة مثلًا:

Map Object
صياغة الاستدعاء 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
};

// loop over values
for (let value of Object.values(user)) {
  alert(value); // John, then 30
}
Object.keys/values/entries تتجاهل هذه التوابِع الخاصيات الرمزية

كما تتجاهل حلقة for…in الخاصيات التي تستعمل Symbol(…)‎ مفاتيح لها، فهذه التوابِع أعلاه تتجاهلها أيضًا

غالبًا يكون هذا ما نريد، ولكن لو أردت المفاتيح الرمزية أيضًا، فعليك استعمال التابِع المنفصل Object.getOwnPropertySymbols إذ يُعيد مصفوفة بالمفاتيح الرمزية فقط. هناك أيضًا التابِع Reflect.ownKeys(obj) إذ يُعيد المفاتيح كلها.

تعديل محتوى الكائنات

ليس للكائنات تلك التوابِع المفيدة المُتاحة للعناصر (مثل map وfilter وغيرها). لو أردنا تطبيق هذه التوابِع على الكائنات فيجب أوّلًا استعمال Object.entries وبعدها Object.fromEntries:

  1. استعمل Object.entries(obj)‎ لتأخذ مصفوفة لها أزواج ”مفتاح/قيمة“ من الكائن obj.
  2. استعمل توابِع المصفوفات على تلك المصفوفة (مثلًا map).
  3. استعمل 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

افتح sandbox بالإختبارات.

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
}

افتح الحل الإختبارات في sandbox.

الأهمية: 5

اكتب دالة باسم count(obj)‎ تُعيد عدد الخاصيات داخل الكائن:

let user = {
  name: "John",
  age: 30
};

alert(count(user)); // 2

حاوِل أن تكون الشيفرة بأصغر ما أمكن.

افتح sandbox بالإختبارات.

function count(obj) {
  return Object.keys(obj).length;
}

افتح الحل الإختبارات في sandbox.

خريطة الدورة التعليمية

التعليقات

إقرأ هذا قبل أن تضع تعليقًا…
  • إذا كان لديك اقتراحات أو تريد تحسينًا - من فضلك من فضلك إفتح موضوعًا فى جيتهاب أو شارك بنفسك بدلًا من التعليقات.
  • إذا لم تستطع أن تفهم شيئّا فى المقال - وضّح ماهو.
  • إذا كنت تريد عرض كود استخدم عنصر <code> ، وللكثير من السطور استخدم <pre>، ولأكثر من 10 سطور استخدم (plnkr, JSBin, codepen…)