خطای Cannot read properties of undefined چیست و چطور رفع می‌شود

خطای Cannot read properties of undefined چیست و چطور رفع می‌شود
در این مقاله می‌خوانید
  1. خطا دقیقاً چه می‌گوید
  2. تفاوت با null
  3. پنج علت رایج
  4. ۱. داده هنوز از سرور نرسیده
  5. ۲. ساختار پاسخ آن چیزی نیست که فکر می‌کردید
  6. ۳. آرایه خالی است
  7. ۴. عنصر DOM پیدا نشده
  8. ۵. مقدار بازگشتی تابع در همهٔ مسیرها یکسان نیست
  9. چطور رفعش کنیم
  10. Optional chaining — کوتاه‌ترین راه
  11. مقدار پیش‌فرض
  12. محافظ زودهنگام
  13. در مبدأ درستش کنید
  14. در فریم‌ورک‌ها چه شکلی دارد
  15. React
  16. Vue
  17. وردپرس و کد بدون فریم‌ورک
  18. یک بار قدم‌به‌قدم پیدایش کنیم
  19. وقتی خطا فقط در production است
  20. خطاهای هم‌خانواده
  21. پیشگیری
  22. جمع‌بندی
  23. منابع و مطالعهٔ بیشتر

اگر یک خطا باشد که هر توسعه‌دهندهٔ جاوااسکریپت آن را دیده باشد، همین است:

TypeError: Cannot read properties of undefined (reading 'name')

خبر خوب اینکه پیام این خطا دقیقاً می‌گوید چه شده. خبر بد اینکه نمی‌گوید چرا — و همان «چرا» است که وقت می‌برد.

خطا دقیقاً چه می‌گوید

جمله را از آخر بخوانید: reading 'name' یعنی می‌خواستید ویژگی name را بخوانید. of undefined یعنی چیزی که می‌خواستید name را از آن بخوانید، undefined بود.

پس در کدی مثل user.name، مشکل از name نیست — مشکل این است که user وجود ندارد. این تفکیک مهم است، چون خیلی‌ها شروع می‌کنند به گشتن دنبال name در حالی که باید دنبال user بگردند.

در نسخه‌های قدیمی‌تر مرورگرها همین خطا با عبارت Cannot read property 'name' of undefined نمایش داده می‌شد. تفاوتشان فقط در متن است، نه در معنا.

تفاوت با null

اگر متغیر null باشد به‌جای undefined، پیام می‌شود Cannot read properties of null. تفاوتشان در ریشه است: undefined معمولاً یعنی «هرگز مقداری نگرفته»، و null یعنی «عمداً خالی گذاشته شده». اولی معمولاً باگ است؛ دومی معمولاً حالتی است که فراموش کرده‌اید مدیریتش کنید.

پنج علت رایج

۱. داده هنوز از سرور نرسیده

شایع‌ترین علت در اپلیکیشن‌های مدرن. کد شما پیش از رسیدن پاسخ اجرا می‌شود:

let user;
fetch('/api/user').then(r => r.json()).then(d => { user = d; });
console.log(user.name);   // خطا — هنوز چیزی نیامده

این حالت در فریم‌ورک‌ها شکل ظریف‌تری دارد: کامپوننت در اولین رندر با داده‌ای خالی رندر می‌شود و شما فقط حالت «داده رسیده» را در نظر گرفته‌اید.

۲. ساختار پاسخ آن چیزی نیست که فکر می‌کردید

// انتظار داشتید: { user: { name: 'علی' } }
// سرور فرستاده:   { data: { user: { name: 'علی' } } }
const name = response.user.name;   // response.user is undefined

این خطا معمولاً بعد از تغییری در سمت بک‌اند ظاهر می‌شود. اولین کاری که باید بکنید نگاه کردن به پاسخ واقعی در تب Network است، نه به مستندات API.

۳. آرایه خالی است

const first = items[0];
console.log(first.title);   // اگر items خالی باشد، خطا

حالت مرزی کلاسیک: با دادهٔ تست کار می‌کند و برای کاربر جدیدی که هنوز چیزی ندارد می‌شکند.

۴. عنصر DOM پیدا نشده

document.getElementById('submit').addEventListener(...)   // خطا اگر عنصر نباشد

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

۵. مقدار بازگشتی تابع در همهٔ مسیرها یکسان نیست

function findUser(id) {
  for (const u of users) if (u.id === id) return u;
  // اگر پیدا نشود، به‌طور ضمنی undefined برمی‌گرداند
}
findUser(99).name;   // خطا

چطور رفعش کنیم

Optional chaining — کوتاه‌ترین راه

const name = user?.name;              // اگر user نباشد، undefined می‌دهد نه خطا
const city = user?.address?.city;     // زنجیره‌ای
const first = items?.[0]?.title;      // روی آرایه هم کار می‌کند

ولی یک هشدار مهم: optional chaining خطا را ساکت می‌کند، نه اینکه مشکل را حل کند. اگر user نباید undefined می‌بود، شما فقط باگ را از یک TypeError پرسروصدا به یک مقدار خالی خاموش تبدیل کرده‌اید — و خطای خاموش سخت‌تر پیدا می‌شود.

قاعده: اگر undefined بودن حالت معتبری است، از ?. استفاده کنید. اگر نیست، ریشه را درست کنید.

مقدار پیش‌فرض

const name = user?.name ?? 'کاربر مهمان';

عملگر ?? فقط برای null و undefined عمل می‌کند، برخلاف || که رشتهٔ خالی و عدد صفر را هم رد می‌کند — تفاوتی که خودش منبع باگ است.

محافظ زودهنگام

function render(user) {
  if (!user) return renderLoading();
  return renderProfile(user);
}

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

در مبدأ درستش کنید

اگر تابعی گاهی چیزی برنمی‌گرداند، این را صریح کنید:

function findUser(id) {
  return users.find(u => u.id === id) ?? null;   // خالی بودن، صریح و عمدی
}

در فریم‌ورک‌ها چه شکلی دارد

React

رایج‌ترین حالت، رندر اول است. کامپوننت با حالت اولیهٔ خالی رندر می‌شود و شما فقط حالت «داده رسیده» را نوشته‌اید:

const [user, setUser] = useState();      // undefined در رندر اول
return <h1>{user.name}</h1>;              // خطا

// درست:
const [user, setUser] = useState(null);
if (!user) return <Spinner />;
return <h1>{user.name}</h1>;

یک نکته: اگر این خطا رخ دهد و مرز خطا نداشته باشید، کل درخت React از کار می‌افتد و کاربر صفحهٔ سفید می‌بیند — نه فقط آن بخش.

Vue

الگوی مشابه، ولی چون قالب Vue خطاهای دسترسی را در سطح اول نادیده می‌گیرد، مشکل معمولاً در زنجیره‌های عمیق‌تر بروز می‌کند:

<!-- امن است حتی اگر user نباشد -->
{{ user.name }}
<!-- خطا می‌دهد -->
{{ user.address.city }}

راه‌حل همان است: v-if برای حالت بارگذاری، یا زنجیرهٔ اختیاری در قالب.

وردپرس و کد بدون فریم‌ورک

اینجا معمولاً مشکل ترتیب اجراست: اسکریپت در <head> قرار گرفته و پیش از ساخته شدن عناصر صفحه اجرا می‌شود. یا اسکریپتی که فقط برای یک صفحه نوشته شده، روی همهٔ صفحات بارگذاری می‌شود.

یک بار قدم‌به‌قدم پیدایش کنیم

فرض کنید این خطا را در داشبورد رصد خطا می‌بینید. مسیر عملی:

  • ۱. خط اول stack trace را بخوانید که به کد خودتان اشاره می‌کند. اگر همه‌چیز مبهم است، source map ندارید و باید اول آن را حل کنید.
  • ۲. ببینید کدام متغیر undefined است. پیام خطا می‌گوید کدام ویژگی خوانده می‌شد؛ چیزی که قبل از آن نقطه است، مقصر است.
  • ۳. بپرسید این متغیر از کجا می‌آید. پاسخ سرور؟ حالت کامپوننت؟ پارامتر تابع؟
  • ۴. اگر از سرور می‌آید، پاسخ واقعی را ببینید — نه مستندات را. تب Network یا breadcrumbهای ثبت‌شده.
  • ۵. الگو را در کاربران متأثر بگردید. همه‌شان کاربر جدیدند؟ همه‌شان یک مرورگر دارند؟ این معمولاً مستقیم به حالت مرزی فراموش‌شده می‌رسد.

وقتی خطا فقط در production است

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

برای پیدا کردنش سه چیز لازم دارید:

  • Source map، وگرنه stack trace کد فشرده به شما هیچ نمی‌گوید.
  • مسیر کاربر تا لحظهٔ خطا، تا بفهمید کدام صفحه و کدام عمل به اینجا رسید.
  • اطلاعات کاربر و مرورگر، چون معمولاً الگویی وجود دارد — همهٔ متأثران یک ویژگی مشترک دارند.

بدون این‌ها فقط می‌دانید «خطایی هست»؛ با این‌ها می‌دانید «برای کاربرانی که پروفایل ناقص دارند، در صفحهٔ تسویه، خطا می‌دهد» — و این جمله تقریباً خودش راه‌حل را می‌گوید.

خطاهای هم‌خانواده

وقتی این خطا را فهمیدید، چند خطای نزدیک هم برایتان روشن می‌شوند — همه‌شان یک ریشه دارند: فرض کردن چیزی که نبود.

  • Cannot read properties of null — همان خطا، ولی مقدار عمداً خالی گذاشته شده. معمولاً یعنی حالتی را که خودتان تعریف کرده‌اید مدیریت نکرده‌اید.
  • x is not a function — خویشاوند نزدیک. چیزی که صدا زدید وجود دارد ولی تابع نیست؛ معمولاً غلط املایی در نام متد، یا شیئی که ساختارش آن چیزی نیست که فکر می‌کردید.
  • x is not iterable — روی چیزی حلقه زده‌اید که آرایه نیست. تقریباً همیشه یعنی پاسخ سرور به‌جای آرایه، شیء خطا یا null بوده.
  • Cannot read properties of undefined (reading 'map') — ترکیب دو مورد بالا و یکی از رایج‌ترین‌ها در React: فهرستی که هنوز نیامده و شما رویش map زده‌اید.

الگوی مشترک این چهار مورد یک جمله است: کد شما زودتر از داده رسیده است. اگر این را ببینید، معمولاً راه‌حل هم همان است — حالت «هنوز نیامده» را به‌عنوان یک وضعیت واقعی در نظر بگیرید، نه حالت استثنایی.

پیشگیری

  • پاسخ سرور را اعتبارسنجی کنید به‌جای اینکه ساختارش را فرض کنید.
  • حالت بارگذاری را جدی بگیرید. هر داده‌ای که از شبکه می‌آید، سه حالت دارد: در حال آمدن، آمده، شکست خورده. هر سه باید کدی داشته باشند.
  • با دادهٔ خالی تست کنید، نه فقط با دادهٔ کامل. کاربر جدید، فهرست خالی، پروفایل ناقص.
  • TypeScript یا JSDoc بخش بزرگی از این خانوادهٔ خطا را پیش از اجرا می‌گیرند.
  • یک تور ایمنی سراسری بگذارید تا هر موردی که از این‌ها رد شد، دست‌کم دیده شود.

جمع‌بندی

این خطا تقریباً همیشه یک معنا دارد: فرض کردید داده‌ای وجود دارد که در آن لحظه وجود نداشت. رفع سریعش با ?. ممکن است، ولی سؤال درست این است که چرا آن داده نبود — و آیا نبودنش حالت معتبری است یا خودش باگ دیگری. برای نقشهٔ کامل خانواده‌های دیگر خطا، راهنمای جامع خطاهای جاوااسکریپت را ببینید.

منابع و مطالعهٔ بیشتر

باگ‌ماگ را رایگان امتحان کنید

خطاهای سایتتان را خودکار ثبت کنید و بگذارید کاربران با یک کلیک باگ گزارش دهند.

شروع رایگان