۱۰ اوت ۲۰۲۱

متدهای Object.keys، values، entries

بیایید از ساختار داده‌های منحصر به فرد دور شویم و درباره حلقه‌زدن در آنها حرف بزنیم.

در فصل قبل ما متدهای map.keys()، map.values()، map.entries() را دیدیدم.

این متدها کلی هستند و یک توافق عمومی برای استفاده از آنها در ساختارهای داده وجود دارد. اگر ما هر زمان بخواهیم ساختار داده‌ی خودمان را بسازیم، باشد آنها را نیز پیاده‌سازی کنیم.

این‌ها برای ساختارهای زیر پشتیبانی می‌شوند:

  • Map
  • Set
  • Array

شیءهای ساده هم متدهای مشابه را پشتیبانی می‌کنند اما سینتکس آن کمی فرق دارد.

متدهای Object.keys، values، entries

برای شیءهای ساده، متدهای زیر موجود هستند:

لطفا تفاوت‌ها را در نظر داشته باشید (برای مثال در مقایسه با map):

Map شیء
سینتکس فراخوانی map.keys() Object.keys(obj)، اما obj.keys() نه
برمی‌گرداند حلقه‌پذیر آرایه «واقعی»

اولین تفاوت این است که ما باید Object.keys(obj) را صدا بزنیم نه obj.keys().

اما چرا؟ دلیل اصلی آن انعطاف‌پذیری است. به یاد داشته باشید، شیءها پایه تمام ساختارهای پیچیده در جاوااسکریپت هستند. پس ما می‌توانیم خودمان یک شیء مانند data داشته باشیم که متد data.keys() خودش را پیاده‌سازی کند. و ما همچنان می‌توانیم 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); // سپس 30 ،John
}
متد 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(
  // هر جفت را به جفت جدید دیگری تبدیل می‌کنیم map قیمت‌ها را به یک آرایه تبدیل می‌کنیم و با استفاده از
  // شیء را بازمی‌گرداند fromEntries و سپس متد
  Object.entries(prices).map(entry => [entry[0], entry[1] * 2])
);

alert(doublePrices.meat); // 8

ممکن است در نگاه اول سخت بنظر برسد اما بعد از اینکه یکی دوبار از آن استفاده کنید فهم آن راحت می‌شود. ما می‌توانیم زنجیره‌های قدرتمندی از تغییر شکل دادن را با این روش بسازیم.

تمارین

اهمیت: 5

یک شیء salaries داریم که تعداد دلخواهی از حقوق‌ها را شامل می‌شود.

تابع sumSalaries(salaries) بنویسید که جمع تمام حقوق‌ها را با استفاده از Object.values و حلقه‌ی for..of برگرداند.

اگر salaries خالی باشد، نتیجه باید 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
}

یا اگر می‌خواستیم، می‌توانستیم جمع را با استفاده از Object.values و reduce محاسبه کنیم:

Object.values(salaries).reduce((a, b) => a + b) // 650

function sumSalaries(salaries) {

  let sum = 0;
  for (let salary of Object.values(salaries)) {
    sum += salary;
  }

  return sum;
}

باز کردن راه‌حل همراه با تست‌ها درون یک sandbox.

اهمیت: 5

یک تابع count(obj) بنویسید که تعداد ویژگی‌های درون شیء را برگرداند:

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

alert( count(user) ); // 2

سعی کنید تا جایی که می‌توانید کد را کوتاه بنویسید.

پی‌نوشت: ویژگی‌های سمبلی(symbolic properties) را نادیده بگیرید، فقط ویژگی‌های «معمولی» را بشمارید.

باز کردن یک sandbox همراه با تست‌ها.

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

باز کردن راه‌حل همراه با تست‌ها درون یک sandbox.

نقشه آموزش