شهربازی

شهربازی

تمرین یادگیری

مقدمه

برخلاف بسیاری از زبان‌های دیگر، در JavaScript دو موجودیت متفاوت وجود دارد که نبودِ یک مقدار (معنادار) را نشان می‌دهند: یکی null و دیگری undefined.

Null

مقدار اولیه‌ی null به‌عنوان یک «مقدار خالی» عمدی برای متغیرهایی از هر نوع به کار می‌رود.

let name = null;
// name is intentionally set to "empty" because it is not
// available

می‌توانید با استفاده از «عملگر تساوی سخت‌گیرانه» === بررسی کنید که آیا یک متغیر null است یا نه.

let name = null;

name === null;
// => true

Undefined

متغیری که مقداری به آن اختصاص داده نشده باشد، از نوع undefined است.۱

یعنی در حالی که null یک مقدار خالی (اما همچنان یک مقدار) را نشان می‌دهد، undefined نشان‌دهنده‌ی نبود کامل مقدار است. 🤯

undefined در موقعیت‌های مختلفی ظاهر می‌شود.

  • اگر متغیری بدون مقدار (مقداردهی اولیه) اعلام شود، undefined است.
  • اگر بخواهید به مقدار یک کلید ناموجود در یک شیء دسترسی پیدا کنید، undefined دریافت می‌کنید.
  • اگر یک تابع مقداری برنگرداند، نتیجه undefined است.
  • اگر آرگومانی به یک تابع پاس داده نشود، undefined است، مگر اینکه آن آرگومان مقدار پیش‌فرض داشته باشد.
let name;
console.log(name);
// => undefined

می‌توانید با استفاده از عملگر تساوی سخت‌گیرانه‌ی === بررسی کنید که آیا یک متغیر undefined است یا نه.

let name;

name === undefined;
// => true

زنجیره‌سازی اختیاری

اگر بخواهید مقدار تودرتویی را در یک شیء بازیابی کنید اما کلید والد وجود نداشته باشد، JavaScript یک خطا پرتاب می‌کند. برای اینکه به‌سادگی از این وضعیت جلوگیری شود، «زنجیره‌سازی اختیاری» در سال ۲۰۲۰ به مشخصات زبان اضافه شد. با عملگر زنجیره‌سازی اختیاری ?. می‌توانید مطمئن شوید که JavaScript فقط وقتی تلاش می‌کند به کلید تودرتو دسترسی پیدا کند که والد null یا undefined نباشد. در غیر این صورت، undefined برگردانده می‌شود.

const obj = {
  address: {
    street: 'Trincomalee Highway',
    city: 'Batticaloa',
  },
};

obj.address.zipCode;
// => undefined

obj.residence.street;
// => TypeError: Cannot read property 'street' of undefined

obj.residence?.street;
// => undefined

ادغام تهی‌گونه

موقعیت‌هایی وجود دارد که می‌خواهید یک مقدار پیش‌فرض اعمال کنید، در صورتی که متغیر null یا undefined باشد (و فقط در همین حالت). برای این کار، عملگر «ادغام تهی‌گونه» ?? در سال ۲۰۲۰ معرفی شد. این عملگر تنها زمانی عملوند سمت راست را برمی‌گرداند که عملوند سمت چپ null یا undefined باشد. در غیر این صورت، عملوند سمت چپ برگردانده می‌شود.

let amount = null;
amount = amount ?? 1;
// => 1

amount = 0;
amount = amount ?? 1;
// => 0

[۱] Undefined، MDN. (۲۰۲۱). https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined (بازبینی‌شده در ۴ ژوئن ۲۰۲۱).

دستورالعمل‌ها

وظیفه‌ی شما تأمین و نگهداری بخش‌هایی از سیستم فناوری اطلاعات یک شهربازی است. به‌ویژه، شما مسئول برنامه‌ای هستید که بازدیدکنندگان و بلیت‌ها را مدیریت می‌کند.

ابتدا یک بازدیدکننده‌ی جدید در سیستم می‌سازید. سپس تابعی برای ابطال بلیت می‌نویسید. در کارهای ۳ و ۴، روی سیستم رهگیری بلیت کار می‌کنید که به جلوگیری از جعل کمک می‌کند. در پایان، به تطبیق سیستم با الزامات قانونی جدید کمک می‌کنید.

1. ساخت بازدیدکننده‌ی جدید

وقتی بازدیدکنندگان برای نخستین بار به شهربازی می‌آیند، باید با وارد کردن اسم و سن خود در یک ترمینال و پذیرفتن شرایط و ضوابط، ثبت‌نام کنند. البته باید یک بلیت هم بخرند. هر بلیت یک شناسه دارد، مانند H32AZ123.

تابعی به اسم createVisitor بنویسید که سه آرگومان می‌پذیرد.

  • اسم بازدیدکننده.
  • سن بازدیدکننده.
  • شناسه‌ی بلیتی که بازدیدکننده خریده است.

تابع باید یک «شیء» برگرداند که این اطلاعات را در خود نگه می‌دارد. کلیدهای شیء باید name، age و ticketId باشند.

createVisitor('Verena Nardi', 45, 'H32AZ123');
// => { name: 'Verena Nardi', age: 45, ticketId: 'H32AZ123' }

2. ابطال بلیت

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

یعنی وقتی بازدیدکننده‌ای پارک را ترک می‌کند، فقط بلیت او باید باطل شود و بقیه‌ی شیء بازدیدکننده باید دست‌نخورده بماند. تابع revokeTicket را پیاده‌سازی کنید که یک شیء بازدیدکننده می‌پذیرد، شناسه‌ی بلیت را روی null قرار می‌دهد و سپس شیء را برمی‌گرداند.

const visitor = {
  name: 'Verena Nardi',
  age: 45,
  ticketId: 'H32AZ123',
};

revokeTicket(visitor);
// => { name: 'Verena Nardi', age: 45, ticketId: null }

3. تعیین وضعیت بلیت

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

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

تابعی به اسم ticketStatus پیاده‌سازی کنید که شیء رهگیری و یک شناسه‌ی بلیت را به عنوان آرگومان می‌پذیرد. این تابع باید یکی از نتایج زیر را برگرداند.

  • 'unknown ticket id' اگر شناسه در شیء رهگیری پیدا نشود
  • 'not sold' اگر بلیت چاپ شده باشد اما فروخته نشده باشد
  • 'sold to {name}' که در آن {name} اسم بازدیدکننده است، اگر بلیت فروخته شده باشد
const tickets = {
  '0H2AZ123': null,
  '23LA9T41': 'Verena Nardi',
};

ticketStatus(tickets, 'RE90VAW7');
// => 'unknown ticket id'

ticketStatus(tickets, '0H2AZ123');
// => 'not sold'

ticketStatus(tickets, '23LA9T41');
// => 'sold to Verena Nardi'

4. بهبود پاسخ وضعیت بلیت

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

تابعی به اسم simpleTicketStatus بنویسید که همان آرگومان‌های ticketStatus در کار ۳ را می‌پذیرد. این تابع فقط یکی از دو نتیجه‌ی متفاوت را برمی‌گرداند.

  • اسم بازدیدکننده، اگر بلیت فروخته شده باشد
  • 'invalid ticket !!!' اگر بلیت هنوز فروخته نشده باشد یا شناسه در شیء رهگیری پیدا نشود
const tickets = {
  '0H2AZ123': null,
  '23LA9T41': 'Verena Nardi',
};

simpleTicketStatus(tickets, '23LA9T41');
// => 'Verena Nardi'

simpleTicketStatus(tickets, '0H2AZ123');
// => 'invalid ticket !!!'

simpleTicketStatus(tickets, 'RE90VAW7');
// => 'invalid ticket !!!'

5. تعیین نسخه‌ی شرایط و ضوابط

به دلیل الزامات قانونی جدید، شیءهای بازدیدکننده‌ی تازه‌ساخته‌شده اکنون اطلاعات مفصلی هم درباره‌ی «شرایط و ضوابط عمومی» (GTC) که کاربر پذیرفته است، در خود دارند. در ادامه نمونه‌ای از شیء بازدیدکننده‌ی جدید را می‌بینید.

صندوقدارهای شهربازی اکنون باید بررسی کنند که آیا بازدیدکننده‌ای نیاز به امضای نسخه‌ی جدیدی از GTC دارد. برای این کار، تابعی به اسم gtcVersion پیاده‌سازی کنید که یک شیء بازدیدکننده را به عنوان آرگومان می‌پذیرد و اگر اطلاعات نسخه‌ی GTC موجود باشد، آن را برمی‌گرداند. اگر اطلاعات نسخه موجود نباشد، هیچ مقداری نباید برگردانده شود.

const visitorNew = {
  name: 'Verena Nardi',
  age: 45,
  ticketId: 'H32AZ123',
  gtc: {
    signed: true,
    version: '2.1',
  },
};

gtcVersion(visitorNew);
// => '2.1'

const visitorOld = {
  name: 'Verena Nardi',
  age: 45,
  ticketId: 'H32AZ123',
};

gtcVersion(visitorOld);
// => undefined
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
JavaScript Exercism

آماده‌اید شهربازی را شروع کنید؟

در Exercism ثبت‌نام کنید تا JavaScript را همراه با 37 مفهوم159 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.