من مهدی ام یک مهندس نرم افزار. اینجا باغچه دیجیتال منه و از پروژهها، آموزشها، تفکرات و هر چیز دیگری که میخوام به دنیا نشان دهم، اینجا مینویسم
زنجیره اختیاری یا Optional Chaining در جاوااسکریپت
زنجیره ای اختیاری روشی بدون خطا برای دستیابی به ویژگی های(properties) داخلی شی است حتی در زمانی که ویژگی میانی وجود نداشته باشد
مشکل ویژگیهای (property) که وجود ندارند
اگر به تازگی شروع به خواندن آموزش و یادگیری جاوا اسکریپت کرده اید ، شاید این مشکل را هنوز لمس نکرده اید ، اما این یک مشکل کاملاً رایج است.
برای مثال, بیاید یک شی(object) برای ذخیره کردن اطلاعات کاربرانمان در نظر بگیریم. اکثر کاربران ما ویژگی(property) آدرس را در user.address
و خیابان را در user.address.street
را دارند ولی بعضی از انان این اطلاعات را ارائه نکرده اند.
در همچین مثالی تلاش ما برای دریافت مقدار user.address.street
, برای کاربری که آدرس ندارد با خطا مواجه شود :
let user = {}; // یک کاربر بدون ویژگی "address"
alert(user.address.street); // خطا
این یک خروجی قابل حدس است٬ جاوااسکریپت اینگونه کار میکند٬تا زمانی که user.address
برابر با undefined
است تلاش برای گرفتن آن با خطا مواجه میشود. ولی در بسیاری از موارد عملی ، ما ترجیح می دهیم به جای خطا ، undefined
را دریافت کنیم (به معنای "بدون خیابان").
یا مثالی دیگر در توسعه وب٬ ما میخواهیم اطلاعاتی در مورد اِلمانی در صفحه را بگیریم.این اِلمان توسط این عبارت document.querySelector('.elem')
گرفته میشود که ممکن است گاهی وجود نداشته باشد:
document.querySelector('.elem') // خواهد شد اگر المنت وجود نداشته باشد null
let html = document.querySelector('.elem'); // اگر باشد خطا خواهد داد NULL
یکبار دیگر٬ اگر اِلمان وجود نداشته باشد ما با مقدار NULL نمیتوانیم به دسترسی داشته باشیم. و در بعضی موارد وقتی که نبود اِلمان طبیعی است ، ما می خواهیم از خطا جلوگیری کنیم و فقط "html = null" را قبول کنیم.
چگونه میتوانیم از این استفاده کنیم ؟
راهحل روشن این است که مقدار آن را با if
یا عمگر شرطی ?
بررسی کنیم قبل از اینکه به ویژگی (property) آن دسترسی پیدا کنیم
let user = {};
alert(user.address ? user.address.street : undefined);
الان بدون خطا کار میکند... ولی اصلا زیبا نیست. همانطور که میبینید مقدار"user.address"
دوبار در کد تکرار شده است. برای دسترسی به ویژگیهای(property) با تو در تویی زیاد نیاز به تکرار بیشتری لازم است و این مشکل ایجاد میکند.
برای مثال بیاید مقدار عبارت user.address.street.name
را بگیریم.
در این صورت ما باید هم user.address
و user.address.street
را بررسی کنیم :
let user = {}; // کاربر بدون آدرس
alert(user.address ? user.address.street ? user.address.street.name : null : null);
این افتضاح است یک نفر ممکن حتی با درک این کد مشکل داشته باشد.
قبل از اینکه زنجیره اختیاری به جاوااسکریپت اضافه شود مردم از عملگر &&
برای بعضی مواقع استفاده میکردند:
نگران نباشید :) ٬ راه های بهتری هم هست میتوانیم از عملگر &&
استفاده کنیم.
let user = {}; // کاربر بدون آدرس
alert( user.address && user.address.street && user.address.street.name ); // undefined (بدون خطا)
اند(AND) کردن کل مسیر رسیدن به ویژگی ، وجود همه ویژگی ها(property) را تضمین می کند(اگر ارزیابی متوقف نشود) ، اما نوشتن آن دست و پا گیر است.
همانطور که میبنید نام ویژگی ها همچنان در کد تکرار میشوند. به طور مثال در قطعه کد بالا user.address
سه بار تکرار شده است.
و حالا در نهایت زنجیره اختیاری آمده است که ما را نجات دهد!
زنجیره اختیاری
زنجیره ای اختیاری ?.
بررسی را متوقف میکند اگر مقدار قبل از قسمت ?.
برابر با undefined
یا null
باشد و مقدار undefined
را برمیگرداند.
یا به عبارت دیگر value?.prop
:
- برابر است با
value.prop
اگرvalue
وجود داشته باشد - در غیر اینصورت (زمانی که
value
برابر باundefined/null
است) مقدارundefined
را برمیگرداند.
.?
این یک دسترسی مطمئن به user.address.street
است:
let user = {}; // کاربر بدون آدرس
alert( user?.address?.street ); // undefined (بدون خطا)
حالا کد خیلی کوتاهتر و تمیزتر است و بدون هیچ تکرار اضافهای :)
خواندن ویژگی(property) آدرس با user?.address
کار خواهد کرد حتی زمانی هم که شی(آبجکت) user
وجود ندارد :
let user = null;
alert( user?.address ); // undefined
alert( user?.address.street ); // undefined
لطفا توجه داشته باشید : سینتکس ?.
مقدارهای قبلی را اختیاری میکند نه مقدارهای جلوی آن را.
در مثال بالا user?.
به user
مقدار null/undefined
خواهد داد.
در مثال بالا user?.address.street
فقط به user
اجازه میدهد که null/undefined
باشد. مثلا در این کد user?.address.street.name
عبارت .?
اجازه میدهد که user
برابر با null/undefined
باشد. این همه کاری است که انجام میدهد.
ویژگی های جلویی به سبک معمولی به ویژگی ها دسترسی دارند.اگر ما میخواهیم بعضی از ویژگی ها را اختیاری کنیم میتوانیم تعداد بیشتری از .
را با .?
جایگزین کنیم
از طرف دیگر ، اگر user
وجود داشته باشد ، پس باید ویژگی user.address
داشته باشد ، در غیر این صورت user؟.address.street
در نقطه دوم خطا می دهد.
ما باید از `?.` فقط زمانی استفاده کنیم که عدم وجود چیزی اشکالی ندارد.برای مثال اگر طبق منطق و لاجیک ما باید شی(object)`user` وجود داشته باشد ولی address اختیاری است. پس ما باید اینگونه بنویسیم user.address?.street نه user?.address?.street
بنابراین ، اگر تصادفاً به دلیل اشتباهی user برابر با undefined باشد، شاهد یک خطای برنامه نویسی در مورد آن خواهیم بود و آن را برطرف خواهیم کرد.
برای زنجیره اختیاری باید متغیر حتما تعریف شده باشد ( let/const/var user
یا توابع ). زنجیره ای اختیاری فقط برای متغیرهای تعریف شده کار می کند.
// ReferenceError: user is not defined
user?.address;
از زنجیره اختیاری میتوان برای صدا زدن توابع هم استفاده کرد :
let userAdmin = {
admin() {
alert("I am admin");
}
};
let userGuest = {};
userAdmin.admin?.(); // I am admin
userGuest.admin?.(); // هیچی (هیچ متدی نیست)
اگر ما میخواهیم از براکت به جای نقطه برای دسترسی به ویژگی(property) استفاده کنیم زنجیره اختیاری برای آن حالت هم کارایی دارد.
let user1 = {
firstName: "John"
};
let user2 = null;
let key = "firstName"
alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
alert( user1?.[key]?.something?.not?.existing); // undefined
خلاصه
سینتکس ?.
سه حالت دارد:
- حالت اول:
obj?.prop
- مقدار obj.prop
را برمیگرداند اگرobj
وجود داشته باشد در غیر اینصورت مقدارundefined
را برمیگرداند - حالت دوم:
[obj?.[prop
- مقدار [obj.[prop
را برمیگرداند اگرobj
وجود داشته باشد در غیر اینصورت مقدارundefined
را برمیگرداند - حالت سوم:
()obj.method()
- obj?.method
را صدا میزند اگرobj
وجود داشته باشد در غیر اینصورت مقدارundefined
را برمیگرداند
همانطور که می بینیم ، همه آنها ساده و آسان برای استفاده هستند. ?.
سمت چپ را از نظر null/undefined
بررسی می کند و اجازه می دهد تا ارزیابی ادامه یابد اگر برابر باnull/undefined
نباشد.
زنجیر ?.
امکان دسترسی به خواص تودرتو را هم فراهم میکند.
با این حال هنوز ما باید ?.
را با دقت اعمال کنیم ، فقط درصورتی قابل قبول است که سمت چپ ممکن است وجود نداشته باشد.با این حال خطاهای برنامه نویسی را از ما مخفی نمیکند اگر آنها اتفاق بیافتند.
اگر از جاوا اسکریپت کارهای حرفه ای باشید، یا برای حرفه ای شدن در این زمینه تلاش کرده باشید، حتما سایت javascript.info رو میشناسید
این سایت آموزشهای بسیار کامل و عمیق از زبان جاوا اسکریپت رو به صورت متنی و متن باز منتشر میکنه.
این آموزش ها توی اکانت سازمانی javascript.info در گیتهاب وجود داره و تا به این لحظه به حدود ۵۰ زبان دنیا ترجمه شده (یا در حال ترجمه هست).
وقتی ترجمه ی یک زبان به حد نصابی میرسه، ساب دومینی برای اون زبان در javascript.info ساخته میشه. برای نمونه tr.javascript.info در حال حاضر این آموزش ها رو به زبان ترکی نمایش میده.
خوشبختانه با تلاش تعدادی از علاقه مندان به کارهای متن باز بخشی از این آموزش ها به فارسی هم ترجمه شده(این مقاله هم ترجمه یکی از قسمت هاست) و میتونید برای یادگیری و یا ترجمه ، به ریپازیتوری رسمی زبان فارسی در آدرس پایین سر بزنید و شماهم مشارکت(contribute) کنید:
لینک
به امید روزی که fa.javascript.info رو ببینیم ?
پ.ن: گروه تلگرامی ای برای ارتباط بهتر javascript کارها ایجاد کردیم :t.me/jsforeveryone
مطلبی دیگر در همین موضوع
ایما: نخستین فونت جدانویس و ماژولار فارسی
مطلبی دیگر در همین موضوع
شروع کار با فالکون – قسمت اول: ساختار پوشه ها
بر اساس علایق شما
داستان یک پرداخت؛ مسابقه نویسندگی پیمان در ویرگول