جاوااسکریپت - چگونه میتوانم از خطاهای «نمیتوان خصوصیت را از undefined خواند» جلوگیری کنم؟
در کد من، با آرایهای سروکار دارم که برخی از ورودیهای آن شامل چندین شیء تو در تو هستند، در حالی که برخی دیگر اینگونه نیستند. این شبیه چیزی است که در ادامه آمده است:
// Where this array is hundreds of entries long, with a mix
// of the two examples given
var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];
این برای من مشکل ایجاد میکند، چون گاهی نیاز دارم از طریق آرایه تکرار کنم و ناسازگاری باعث میشود خطاهایی مانند این دریافت کنم:
for (i=0; i<test.length; i++) {
// OK, on i==0, but 'cannot read property of undefined' on i==1
console.log(a.b.c);
}
من آگاه هستم که میتوانم بنویسم if(a.b){ console.log(a.b.c)}، اما این در مواردی که تا ۵ یا ۶ شیء در یکدیگر تو در تو هستند، فوقالعاده خستهکننده است. آیا روش دیگری (آسانتر) وجود دارد که بتوانم فقط زمانی که وجود دارد، console.log را انجام دهد، اما بدون اینکه خطا بدهد؟
پاسخ شماره ۱
بهروزرسانی:
- اگر از جاوااسکریپت طبق ECMAScript 2020 یا بعد از آن استفاده میکنید، به زنجیرهسازی اختیاری مراجعه کنید.
- تایپاسکریپت از نسخه ۳.۷ پشتیبانی از زنجیرهسازی اختیاری را اضافه کرده است.
// use it like this
obj?.a?.lot?.of?.properties
راهحل برای جاوااسکریپت قبل از ECMASCript 2020 یا تایپاسکریپت نسخه قدیمیتر از 3.7:
یک راه حل سریع استفاده از یک تابع کمکی try/catch با تابع فلش ES6 است:
function getSafe(fn, defaultVal) {
try {
return fn();
} catch (e) {
return defaultVal;
}
}
// use it like this
console.log(getSafe(() => obj.a.lot.of.properties));
// or add an optional default value
console.log(getSafe(() => obj.a.lot.of.properties, 'nothing'));پاسخ شماره ۲
کاری که انجام میدهید یک استثنا ایجاد میکند (و بهحق هم هست). شما همیشه میتوانید این کار را انجام دهید:
try{
window.a.b.c
}catch(e){
console.log("YO",e)
}
اما من این کار را نمیکنم، در عوض به مورد استفاده خود فکر کنید.
چرا به دادههایی که ۶ سطح تو در تو هستند و با آنها آشنایی ندارید دسترسی پیدا میکنید؟ کدام مورد استفاده این را توجیه میکند؟
معمولاً شما دوست دارید واقعاً تأیید کنید با چه نوع شیءای سر و کار دارید.
همچنین، به طور جانبی نباید از دستوراتی مانند if(a.b) استفاده کنید زیرا اگر a.b برابر با 0 باشد یا حتی اگر "0" باشد، مقدار false برمیگرداند. در عوض بررسی کنید که a.b !== undefined باشد
پاسخ شماره ۳
اگر من سؤال شما را به درستی درک کرده باشم، شما میخواهید ایمنترین روش برای تشخیص اینکه آیا یک شیء دارای یک ویژگی است را بدانید.
سادهترین راه استفاده از عملگر in است.
window.a = "aString";
//window should have 'a' property
//lets test if it exists
if ("a" in window){
//true
}
if ("b" in window){
//false
}
البته میتوانید این را به اندازهای که میخواهید تو در تو کنید
if ("a" in window.b.c) { }
مطمئن نیستم که این مفید باشد.
پاسخ شماره ۴
این را امتحان کنید. اگر a.b برابر با undefined باشد، بدون هیچ استثنایی از عبارت if خارج خواهد شد.
if (a.b && a.b.c) {
console.log(a.b.c);
}
پاسخ شماره ۵
اگر از lodash استفاده میکنید، میتوانید از تابع has آنها استفاده کنید. این تابع شبیه به "in" بومی است، اما مسیرها را نیز پشتیبانی میکند.
var testObject = {a: {b: {c: 'walrus'}}};
if(_.has(testObject, 'a.b.c')) {
//Safely access your walrus here
}
