۹ روش برای کار با اشیا در جاوا اسکریپت — راهنمای کاربردی

۱۳۲ بازدید
آخرین به‌روزرسانی: ۰۷ شهریور ۱۴۰۲
زمان مطالعه: ۷ دقیقه
۹ روش برای کار با اشیا در جاوا اسکریپت — راهنمای کاربردی

جاوا اسکریپت مانند بسیاری از زبان‌های دیگر دارای ترفندهای زیادی برای اجرای وظایف آسان و دشوار است. در این مقاله با 9 روش برای کار با اشیا در جاوا اسکریپت آشنا می‌شویم. در این مقاله فهرست کوتاهی از روش‌های کار با اشیا ارائه می‌کنیم. برخی موارد جالب هستند، برخی موارد مشهور هستند و برخی دیگر نیز صرفاً به منظور داشتن اطلاعات ارائه شده‌اند. اگر به کدنویسی جاوا اسکریپت علاقه‌مند باشید، احتمالاً موافق هستید که کار با اشیا نسبت به کار با انواع دیگر جذابیت بیشتری دارد. با ما تا انتهای این راهنما همراه باشید.

1. ایجاد واقعی شیئ خالی

همه می‌دانیم که امکان ایجاد شیء در جاوا اسکریپت وجود دارد، اما آیا می‌دانید که امکان ایجاد شیء خالی نیز وجود دارد؟

به مثال زیر توجه کنید:

1const myEmptyObject = {}

با استفاده از دستور فوق می‌توانید اشیای خالی ساده‌ای ایجاد کنید. با این حال به صورت داخلی این اشیا واقعاً خالی نیستند زیرا ما در عمل کاری مانند زیر انجام داده‌ایم:

1Object.create(Object.prototype)

دستور فوق یک شیء ایجاد می‌کند که به مشخصه‌های درون Object.prototype دسترسی داشته باشیم که در ابتدای زنجیره پروتوتایپ قرار دارد. این بدان معنی است که می‌توانید از متدهایی مانند زیر استفاده کنید:

1myEmptyObject.toString()

برای ایجاد واقعی شیء خالی باید در زمان استفاده از آن null ارسال شود:

1const myTrulyEmptyObject = Object.create(null)

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

2. ادغام اشیا - روش شماره یک (Object.assign)

1const novice = { username: 'henry123', level: 10, hp: 100 }
2
3function transform(target) {
4  return Object.assign(target, {
5    fireBolt(player) {
6      player.hp -= 15
7      return this
8    },
9  })
10}
11
12const sorceress = transform(novice)
13const lucy = { username: 'iamlucy', level: 5, hp: 100 }
14
15sorceress.fireBolt(lucy)

زمانی که از متد Object.assign استفاده می‌کنید، باید یک شیء target به عنوان شیئی برای ادغام اشیای اضافی و/یا مشخصه‌ها داشته باشید. شیء هدف آرگومان نخست Object.assign است. هر آرگومان بعد از آن در نهایت در شیء هدف ادغام می‌شود. مستندات رسمی موزیلا در مورد این متد به صورت زیر است:

متد ()Object.assign همه مشخصه‌های شمارش پذیر خود را از یک یا چند شیء منبع به یک شیء هدف کپی می‌کند. در نهایت شیء مقصد بازگشت می‌یابد.

3. ادغام اشیا – روش شماره دو (Spread Syntax)

1const novice = { username: 'henry123', level: 10, hp: 100 }
2
3function transform(target) {
4  return {
5    ...target,
6    fireBolt(player) {
7      player.hp -= 15
8      return this
9    },
10  }
11}
12
13const sorceress = transform(novice)
14const lucy = { username: 'iamlucy', level: 5, hp: 100 }
15
16sorceress.fireBolt(lucy)

زمانی که اشیا را به این روش ادغام می‌کنید، در واقع از عملگر اسپرد روی یک لفظ شیء بهره می‌گیرید. این ساختار در نسخه رسمی ECMAScript 2018 معرفی شده است و از این رو جدید محسوب می‌شود. استفاده از این روش برای ادغام چندین شیء کاملاً ساده است و افراد زیادی استفاده از آن را توصیه می‌کنند زیرا کد همچنان خوانا و تمیز می‌ماند. در واقع تنها کاری که باید انجام دهید تایپ کردن سه‌نقطه است.

گسترش تابع‌های IIFE

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

برای نمونه از آنجا که تابع‌ها در جاوا اسکریپت همچنان شیء هم محسوب می‌شوند، می‌توان با تابع‌ها مانند اشیا رفتار کرد. معنی این حرف آن است که می‌توان آن‌ها را به اطراف ارسال کرد و کارهای جالبی با آن‌ها انجام داد. حتی می‌توان از تابع‌ها برای ادغام در لفظ‌های شیء به روش‌های عجیب مانند زیر استفاده کرد:

1import React from 'react'
2import {
3  EditIcon,
4  DeleteIcon,
5  ResetIcon,
6  TrashIcon,
7  UndoIcon,
8} from '../lib/icons'
9import * as utils from '../utils
10
11export const audioExts = ['mp3', 'mpa', 'ogg', 'wav']
12
13const icons = {
14  edit: {
15    component: EditIcon,
16    onClick: () => window.alert('You clicked the edit component'),
17    name: 'edit',
18  },
19  delete: {
20    component: DeleteIcon,
21    name: 'delete',
22  },
23   // Audio icons
24  // IIFE returning an object
25  ...(function() {
26    return audioExts.reduce((acc, ext) => {
27      acc[ext] = {
28        component: MdAudiotrack,
29        title: 'Audio Track',
30      }
31      return acc
32  })(),
33}

از آنجا که IIFE-ها خود فراخوان هستند، بی‌درنگ شیئی را بازگشت می‌دهیم که باید در شیء icons قرار گیرد. نتیجه همان شیء خواهد بود، اما ادغام خواهد داشت:

1export const audioExts = ['mp3', 'mpa', 'ogg', 'wav']
2
3const icons = {
4  edit: {
5    component: EditIcon,
6    onClick: () => window.alert('You clicked the edit component'),
7    name: 'edit',
8  },
9  delete: {
10    component: DeleteIcon,
11    name: 'delete',
12  },
13  // Merged with audio icons
14  mp3: {
15    component: MdAudiotrack,
16    title: 'Audio Track',
17  },
18  mpa: {
19    component: MdAudiotrack,
20    title: 'Audio Track',
21  },
22  ogg: {
23    component: MdAudiotrack,
24    title: 'Audio Track',
25  },
26  wav: {
27    component: MdAudiotrack,
28    title: 'Audio Track',
29  },
30}

4. بررسی مشخصه‌های موجود در 2020

یک قابلیتی که قطعاً سروصدای زیادی در جامعه توسعه‌دهندگان جاوا اسکریپت ایجاد خواهد کرد، «زنجیره‌سازی اختیاری» (optional chaining) است. عملگر جدید به شکل ?. است و بدون نیاز به اعتبارسنجی صریح تک تک حلقه‌های زنجیره، امکان خواندن مقدار مشخصه‌ای را فراهم می‌سازد که در اعماق یک زنجیره از اشیای به هم متصل قرار دارد. این بدان معنی است که اگر یک ساختمان شیء عمیقاً تودرتو مانند زیر داشته باشید:

1const food = {
2  fruits: {
3    apple: {
4      dates: {
5        expired: '2019-08-14',
6      },
7    },
8  },
9}

دیگر لازم نیست کدهای تکراری مانند زیر بنویسید:

1function getAppleExpirationDate(obj) {
2  if (food.fruits && food.fruits.apple && food.fruits.apple.dates) {
3    return food.fruits.apple.dates.expired
4  }
5}

بدین ترتیب کار هنگام استفاده از زنجیره‌سازی اختیاری بسیار آسان‌تر می‌شود:

1function getAppleExpirationDate(obj) {
2  return food?.fruits?.apple?.dates?.expired
3}

استفاده از این روش در هر جای کد موجب ایجاد کد بسیار تمیزتری می‌شود. مثلاً تابعی مانند زیر:

1function findFatDogs(dog, result = []) {
2  if (dog && dog.children) {
3    return dog.children.reduce((acc, child) => {
4      if (child && child.weight > 100) {
5        return acc.concat(child)
6      } else {
7        return acc.concat(findFatDogs(child))
8      }
9    }, result)
10  }
11  return result
12}

می‌تواند به سادگی به تابع زیر تبدیل شود و در عین حال خوانایی آن نیز حفظ شود:

1function findFatDogs(dog, result = []) {
2  if (dog?.children) {
3    return dog.children.reduce((acc, child) => {
4      return child?.weight > 100
5        ? acc.concat(child)
6        : acc.concat(findFatFrogs(child))
7    }, result)
8  }
9  return result
10}

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

5. فراخوانی اشیا با Overriding

زمانی که اشیا به صورت کلیدهای لفظ‌های شیئی انتساب می‌یابند، به صورت رشته درمی‌آیند. این حالت کاربردهای بسیار زیبایی دارد.

به مثال زیر توجه کنید:

1function Command(name, execute) {
2  this.name = name
3  this.execute = execute
4}
5
6Command.prototype.toString = function() {
7  return this.name
8}
9
10const createCommandHub = function() {
11  const commands = {}
12  return {
13    add(command) {
14      commands[command.name] = command
15    },
16    execute(command, ...args) {
17      return commands[command].execute(...args)
18    },
19  }
20}
21
22const cmds = createCommandHub()
23const talkCommand = new Command('talk', function(wordsToSay) {
24  console.log(wordsToSay)
25})
26const destroyEverythingCommand = new Command('destroyEverything', function() {
27  throw new Error('Destroying everything')
28})
29
30cmds.add(talkCommand)
31cmds.add(destroyEverythingCommand)
32cmds.execute(talkCommand, 'Is talking a talent?')

اگر قطعه کد فوق را اجرا کنید، می‌بیند که کد کار می‌کند و نتیجه به صورت زیر است:

اگر دقیقاً به روش اضافه شدن این دستور نگاه کنید، می‌بینید که باید خطایی مانند زیر صادر کند:

دلیل این که این خطا صادر نمی‌شود، این است که وقتی سازنده Command تعریف شد، ما می‌توانیم متد پروتوتایپ toString را مانند زیر override کنیم:

زمانی که مقادیر انواع غیر ابتدایی به مشخصه‌های یک شیء انتساب یابند، جاوا اسکریپت تلاش می‌کند که آن‌ها را پیش از الصاق کلید، رشته‌ای (Stringify) کند و این کار را با استفاده از متد ‎.toString خود روی پروتوتایپ انجام می‌دهد. reduxjs/toolkit@ از این ترفند بهره می‌گیرد تا امکان ارسال اکشن مستقیماً به صورت کلید ایجاد شود. برای نمونه آن‌ها می‌توانند مستقیماً به صورت کلید استفاده شوند و از این رو تابع reducer انتساب یافته به مقدار ‎.type اکشن نگاشت می‌شود.

6. تخریب ساختار

از جمله امکانات جدیدی که به جاوا اسکریپت اضافه شده است، بحث «تخریب ساختار» (Destructuring) اشیا است:

1const obj = {
2  foods: {
3    apples: ['orange', 'pineapple'],
4  },
5}
6const { foods } = obj
7console.log(foods) // apples: ["orange", "pineapple"]

7. تغییر دادن نام مشخصه‌های تخریب‌ شده

برای تغییر نام مشخصه‌های تخریب‌شده می‌توانید به صورت زیر عمل کنید:

1const obj = {
2  foods: {
3    apples: ['orange', 'pineapple'],
4  },
5}
6const { foods: myFoods } = obj
7console.log(myFoods) // apples: ["orange", "pineapple"]

8. چرخه تکرار روی کلیدهای یک شیئ

یک روش آسان برای تکرار روی کلیدهای یک شیء استفاده از ساختار for in است:

1const obj = {
2  foods: {
3    apples: ['orange', 'pineapple'],
4  },
5  water: {
6    f: '',
7  },
8  tolupa: function() {
9    return this.name
10  },
11}
12
13const { foods } = obj
14
15for (let k in obj) {
16  console.log(k)
17}
18/*
19  result: 
20    "foods"
21    "water"
22    "tolupa"
23*/

9. تکرار روی کلیدهای یک شیئ – روش دوم

یک رویکرد متفاوت برای تعریف چرخه تکرار روی کلیدهای یک شیء استفاده از متد Object.keys است:

1const obj = {
2  foods: {
3    apples: ['orange', 'pineapple'],
4  },
5  water: {
6    f: '',
7  },
8  tolupa: function() {
9    return this.name
10  },
11}
12const { foods } = obj
13const keys = Object.keys(obj)
14console.log(keys)

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

1const people = {
2  bob: {
3    age: 15,
4    gender: 'male',
5  },
6  jessica: {
7    age: 24,
8    gender: 'female',
9  },
10  lucy: {
11    age: 11,
12    gender: 'female',
13  },
14  sally: {
15    age: 14,
16    gender: 'female',
17  },
18}
19
20const { males, females } = Object.keys(people).reduce(
21  (acc, name) => {
22    const person = people[name]
23    if (person.gender === 'male') {
24      acc.males.push(name)
25    } else {
26      acc.females.push(name)
27    }
28    return acc
29  },
30  { males: [], females: [] },
31)
32
33console.log(males) // ["bob"]
34console.log(females) // ["jessica", "lucy", "sally"]

سخن پایانی

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

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
better-programming
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *