optional chaining (?.
) یا یک تابع را فراخوانی میکند و یا این که به ویژگیهای یک آبجکت دسترسی پیدا میکند. اگر آبجکت یا تابع undefined یا null باشد، به جای این که خطا ایجاد شود، به عنوان undefined ارزیابی میگردد. در این مقاله قصد داریم تا مفهوم optional chaining در جاوااسکریپت را بیشتر باهم بررسی کنیم.
اگر مدت زمان زیادی است که با جاوااسکریپت کار میکنیم، احتمالاً کدی را که دقیقاً شبیه کد زیر است دیدهایم:
const street = person && person.address && person.address.street
کد بالا تقریباً کوتاهترین و سادهترین راه برای بررسی اینکه آیا یک آبجکت قبل از دسترسی به ویژگیهای آن undefined یا null است، میباشد. واضح است که این کد خیلی مختصر یا تمیز نیست. به همین دلیل است که جاوااسکریپت در نهایت برای بررسی این کار از یک عملگر optional chaining استفاده میکند.
اساساً ایده optional chaining این است که در جایی که نیاز به دسترسی به ویژگیها یا مقادیر یک آبجکت یا آرایه وجود دارد، و ممکن است این مقادیر undefined یا null باشند، نوشتن کد را آسان میکند.
در ادامه سینتکس اصلی برای optional chaining را بررسی میکنیم تا نحوه عملکرد آن را دقیقتر درک کنیم.
const name = person?.name
در کد بالا یک متغیر person
داریم که ممکن است undefined یا null باشد یا نباشد. با توجه به این که نمیدانیم person
تعریف شده است یا نه، نمیتوانیم مستقیماً به ویژگی name
آن دسترسی داشته باشیم. زیرا اگر person
تعریف نشده باشد، خطای زیر را دریافت میکنیم.
Uncaught TypeError: Cannot read property 'name' of undefined
با استفاده از عملگر optional chaining (?.
)، ما میتوانیم کد خود را طوری بنویسیم که گویی مستقیماً به ویژگی name
دسترسی داریم. اگر person
تعریف نشده باشد، کد ما به جای ارسال خطا، فقط undefined را return میکند. به طور کلی کد بالا مشابه کد زیر است.
const name = person == null ? undefined : person.name
عملگر optional chaining متغیر person
را بررسی میکند تا مطمئن شود که قبل از دسترسی به ویژگی name
تعریف شده است و اگر تعریف نشده باشد، فقط undefined را return میکند. این بدان معناست که ما میتوانیم کد را به صورت زیر بنویسیم.
const street = person?.address?.street
خواندن این کد بسیار راحتتر از کد اصلی است و یکی از بهترین موارد استفاده برای optional chaining میباشد. جاوااسکریپت کاربردهای اضافی زیادی برای optional chaining دارد، که اکثر زبانهای دیگر آن را پیادهسازی نمیکنند.
یکی مهمترین موارد استفاده از optional chaining، انجام optional chaining با فراخوانی تابع است. ابتدا چند کد برای فراخوانی یک تابع روی یک آبجکت که ممکن است تعریف نشده باشد را بررسی میکنیم.
const windowCount = house.getWindowCount && house.getWindowCount()
کدی که داریم متغیر house
را بررسی میکند تا مطمئن شود قبل از اینکه آن تابع را فراخوانی کند، ویژگی به نام getWindowCount
را دارد. واضح است که خواندن این کد به دلیل پیچیدگی که دارد، دشوار است. این جا همان قسمتی است که عملگر optional chaining مطرح میشود.
const windowCount = house.getWindowCount?.()
اکنون ممکن است در ابتدا داشتن نقطه (.
) قبل از پرانتز تابع عجیب به نظر برسد، اما این به این دلیل است که عملگر optional chaining یک علامت سوال همراه با یک نقطه است(?.
)، نه فقط یک علامت سوال تنها. این کد جدید که از عملگر optional chaining استفاده میکند، اکنون بررسی میکند که آیا تابعی به نام getWindowCount
روی متغیر house
تعریف شده است یا خیر و اگر وجود داشته باشد، آن را فراخوانی میکند. اگر آن تابع در متغیر house
وجود نداشته باشد، به جای فراخوانی تابع، فقط undefined را return میکند.
آخرین راه اصلی که میتوانیم از optional chaining استفاده کنیم، آرایهها هستند. اگر میخواهیم بر اساس ایندکس به یک المنت در یک آرایه دسترسی داشته باشیم، اما مطمئن نیستیم که آرایه تعریف شده است یا نه، باید از کدی شبیه به کد زیر استفاده کنیم.
const firstElement = arr && arr[0]
با استفاده از عملگر optional chaining، میتوانیم کدی که داریم را به صورت زیر ساده کنیم.
const firstElement = arr?.[0]
دوباره یک نقطه (.
) قبل از براکت برای دسترسی به یک المنت آرایه ممکن است عجیب به نظر برسد، اما این فقط بخشی از سینتکس optional chaining میباشد. این کد جدید با بررسی اینکه آیا متغیر arr
تعریف شده است یا خیر، کار میکند و سعی دارد به ایندکس آرایه مشخص شده دسترسی پیدا کند. اگر متغیر arr
تعریف نشده باشد، به جای تلاش برای دسترسی به ایندکس آرایه، undefined را return میکند.
این علامت گذاری براکت optional chaining را میتوانیم با آبجکتها نیز مورد استفاده قرار دهیم.
const name = person?.["name"]
اگر میخواهیم به صورت پویا و بر اساس یک رشته به ویژگی یک آبجکت دسترسی داشته باشیم ولی مطمئن نیستیم که آبجکت تعریف شده است یا نه، استفاده از این روش واقعا مفید است.