TypeError: Cannot read properties of undefined (reading 'x')هو الخطأ الأكثر شيوعًا في وقت التشغيل في JavaScript. تصبح الرسالة دقيقة بمجرد أن تتعلم قراءتها، ويكون الإصلاح دائمًا واحدًا من خمسة أنماط. يغطي هذا الدليل كيفية تحديد السبب بسرعة وكيفية منع تكراره.
📋 Table of Contents
- ماذا يعني الخطأ في الواقع
- السبب 1: قراءة البيانات غير المتزامنة قبل وصولها
- لقد كتبت
- يعود
- يقرأ التدمير الخصائص، لذلك يتم طرحه لنفس السبب تمامًا – فقط مع خط مكدس أقل وضوحًا.
- فقدت ملزمتهاthisعندما يتم تمرير أسلوب كرد اتصال،
- تسلسل اختياري
- عندما يظهر الخطأ، اعمل من خلال هذا التسلسل.
- تايب سكريبت
- س: ما الفرق بين هذا و"لا يمكن قراءة خصائص القيمة الخالية"؟
- الخلاصة
ماذا يعني الخطأ في الواقع
لقد حاولت قراءة خاصية من شيء هوundefined. يخبرك الجزء الموجود بين قوسين بالخاصية التي حاولت قراءتها.
const user = undefined;
console.log(user.name);
// TypeError: Cannot read properties of undefined (reading 'name')
البصيرة النقدية:المشكلة ليست في الملكية، بل في الشيء الذي قبل النقطة. عندما ترى(reading 'name')، الخطأ هو أن كل ما يجب أن يحتوي على كائن المستخدم هوundefined. الجميع يفقد الوقت في تصحيح الأخطاءname عندما يجب أن يسألوا لماذاuser فارغ.
في السلسلة، اعمل من اليسار إلى اليمين للعثور على الرابط الأول غير المحدد.
const response = { data: { items: [] } };
console.log(response.data.results.length);
// TypeError: Cannot read properties of undefined (reading 'length')
// 'results' does not exist on data, so response.data.results is undefined.
السبب 1: قراءة البيانات غير المتزامنة قبل وصولها
إلى حد بعيد السبب الأكثر شيوعا في التطبيقات الحقيقية. تبدأ الحالة فارغة، ويتم تشغيل العرض، ولم يتم حل عملية الجلب بعد.
function Profile({ userId }) {
const [user, setUser] = useState(); // undefined on first render
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]);
return <h1>{user.name}</h1>; // throws on the very first render
}
تم الإصلاح عن طريق التهيئة إلى قيمة فارغة معقولة وحماية العرض.
function Profile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
setLoading(true);
fetch(`/api/users/${userId}`)
.then(r => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
})
.then(data => { if (!cancelled) setUser(data); })
.catch(err => { if (!cancelled) console.error(err); })
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, [userId]);
if (loading) return <p>Loading…</p>;
if (!user) return <p>User not found.</p>;
return <h1>{user.name}</h1>;
}
تمنع العلامة أيضًا الخطأ الشائع الثاني: الاستجابة البطيئة منcancelledالسابقة الكتابة فوق البيانات الأحدث بعد تغيير الدعامة.userIdالسبب 2: شكل استجابة واجهة برمجة التطبيقات (API) ليس هو ما افترضته
لقد كتبت
لكن واجهة برمجة التطبيقات ترجعdata.items، أو أنه يغلف كل شيء في{ results: [...] }. من السهل أن تخطئ في هذا بشكل خاص مع Axios، الذي يضيف{ data: { ... } }الخاص به غلاف أعلى جسم الاستجابة.dataقم بتسجيل الاستجابة بالكامل قبل الفهرسة فيها. واحد
// Axios puts the response body in .data — so the payload is often data.data
const response = await axios.get('/api/users');
console.log(response.data.users); // correct
console.log(response.users); // undefined -> throws downstream
يجيب على السؤال على الفور، حيث لا التخمين.console.log(JSON.stringify(response, null, 2))السبب 3: طرق بحث الصفيف التي لم تجد شيئًا
يعود
find عندما لا يتطابق أي عنصر، وهذا هو المصدر الوحيد الأكثر شيوعًا للخطأ في كود التعامل مع القائمة.undefinedتعامل دائمًا مع النتيجة على أنها ربما تكون مفقودة.
const users = [{ id: 1, name: 'Ada' }];
const match = users.find(u => u.id === 99);
console.log(match.name);
// TypeError: Cannot read properties of undefined (reading 'name')
الأمر نفسه ينطبق على
const match = users.find(u => u.id === 99);
if (!match) {
return null; // or throw a clear domain error
}
console.log(match.name);
// Or with optional chaining when a missing value is acceptable:
console.log(match?.name ?? 'Unknown user');
، والذي يُرجعdocument.querySelector عندما لا يتطابق أي شيء، وإلىnull وMap.getالسبب الرابع: تدمير كائن غير محددArray.at.
يقرأ التدمير الخصائص، لذلك يتم طرحه لنفس السبب تمامًا – فقط مع خط مكدس أقل وضوحًا.
قم بإعطاء المعلمة افتراضيًا حتى يكون للتدمير دائمًا كائن للعمل معه.
function greet({ name }) {
return `Hello ${name}`;
}
greet();
// TypeError: Cannot destructure property 'name' of 'undefined'
السبب 5:
function greet({ name = 'friend' } = {}) {
return `Hello ${name}`;
}
greet(); // "Hello friend"
greet({ name: 'Ada' }); // "Hello Ada"
فقدت ملزمتهاthisعندما يتم تمرير أسلوب كرد اتصال،
لم يعد هو الكائن، لذلك تفشل كل خاصية يتم قراءتها عليه.thisقم بربطه، أو استخدم حقل فئة مع وظيفة سهم، والتي تلتقط
class Counter {
constructor() { this.count = 0; }
increment() { this.count++; } // 'this' is undefined when detached
}
const c = new Counter();
button.addEventListener('click', c.increment);
// TypeError: Cannot read properties of undefined (reading 'count')
معجميا.thisالأدوات التي تمنع ذلك
class Counter {
count = 0;
increment = () => { this.count++; }; // arrow field — always bound
}
const c = new Counter();
button.addEventListener('click', c.increment); // works
تسلسل اختياري
دوائر قصيرة إلى بدلا من رمي.undefinedاندماج لاغي
const city = user?.address?.city; // undefined, no throw
const first = users?.[0]?.name; // works on arrays too
const result = api.getUser?.(id); // and on possibly-missing methods
يوفر خيارًا احتياطيًا فقط لـ وnullعلى عكسundefined والذي يحل أيضًا محل|| والسلاسل الفارغة.0استخدم التسلسل الاختياري حيث تكون القيمة المفقودة صالحة بالفعل. لا تبعثرها في كل مكان لإسكات الأخطاء — إذا
const count = data?.count ?? 0; // 0 stays 0
const wrong = data?.count || 0; // a real 0 becomes 0 anyway, but '' becomes 0 too
يجب أن يكون موجودًا دائمًا عند هذه النقطة، فإن إخفاء غيابه يحول الخطأ الصاخب إلى خطأ صامت يظهر لاحقًا دون أي أثر مكدس.userطريقة التصحيح
عندما يظهر الخطأ، اعمل من خلال هذا التسلسل.
اقرأ اسم الخاصية بين قوسين. الخطأ موجود في التعبير
- قبل تلك الخاصية.افتح تتبع المكدس وانقر فوق الإطار العلوي في التعليمات البرمجية الخاصة بك، متجاهلاً إطارات المكتبة.
- قم بتعيين نقطة توقف على هذا السطر وافحص التعبير المحتوي، وليس الخاصية.
- قم بالسير في السلسلة من اليسار إلى اليمين للعثور على الرابط الأول غير المحدد.
- اسأل لماذا هذه القيمة فارغة – هل لم يتم حل عملية الجلب، أو فشل البحث، أو لم يتم تمرير الدعامة مطلقًا؟
- في الإنتاج، تعتبر خرائط المصدر ضرورية. بدونها نقاط التتبع في التعليمات البرمجية المصغرة وهذه العملية مستحيلة.
الوقاية منه هيكليا
تايب سكريبت
يلتقط معظم هذه العناصر في وقت الترجمة، خاصة مع ممكّن. يفرض عليك التعامل مع الحالة غير المحددة قبل تشغيل الكود.strictNullChecksالتحقق من صحة على الحدود.
function getName(user: User | undefined): string {
// Error: 'user' is possibly 'undefined' — caught before runtime
return user.name;
}
تحليل استجابات واجهة برمجة التطبيقات (API) باستخدام أداة التحقق من صحة المخطط مثل Zod بحيث يفشل الشكل غير المتوقع فورًا برسالة واضحة، بدلاً من نشر ثلاث طبقات غير محددة في كود العرض الخاص بك.إرجاع المجموعات الفارغة، غير المحددة.
دالة تقوم بإرجاع بدلا من[] يتيح للمتصلين خريطة النتيجة دون قيد أو شرط.undefinedالأسئلة المتداولة
س: ما الفرق بين هذا و”لا يمكن قراءة خصائص القيمة الخالية”؟
ج: القيمة فقط.
عادة ما يعني أن المتغير لم يتم تعيينه مطلقًا أو أن الخاصية غير موجودة؛ undefined عادةً ما يعني شيئًا ما تعيينه بشكل صريح على أنه فارغ. نهج التصحيح متطابق.nullس: هل يجب علي إضافة تسلسل اختياري في كل مكان؟
س: هل يجب علي إضافة تسلسل اختياري في كل مكان؟
ج: لا. استخدمها عندما تكون القيمة اختيارية بشكل قانوني. يؤدي استخدامه لإسكات خطأ لا تفهمه إلى تحويل العطل مع تتبع المكدس إلى سلوك خاطئ دون أي أثر على الإطلاق.
س: لماذا يعمل محليا ويفشل في الإنتاج؟
ج: عادة التوقيت أو البيانات. تستجيب واجهات برمجة التطبيقات المحلية بشكل أسرع، لذلك تختفي حالات السباق؛ وتحتوي بيانات الإنتاج على أشكال لا تحتوي عليها بيانات الاختبار الخاصة بك، مثل السجلات التي تحتوي على حقول اختيارية مفقودة.
س: كيف يمكنني العثور على الخطأ عندما يعرض تتبع المكدس رمز المكتبة فقط؟
ج: قم بتمكين خرائط المصدر، ثم استخدم “قائمة التجاهل” في Chrome DevTools لإخفاء إطارات إطار العمل بحيث يكون الإطار المرئي الأعلى هو الكود الخاص بك.
س: هل يقوم TypeScript بإلغاء هذا الخطأ تمامًا؟
ج: لا، إنه يزيلها مقابل التعليمات البرمجية التي يمكنه التحقق منها، ولكن البيانات تتجاوز حدود وقت التشغيل – استجابات واجهة برمجة التطبيقات، وتحليل JSON،any casts – لا يزال من الممكن أن تكون غير محددة في وقت التشغيل. التحقق من صحة البيانات الخارجية حتى في TypeScript.
الخلاصة
اصلاحCannot read properties of undefined ميكانيكي بمجرد أن تعرف القاعدة:فالخطأ يكون في التعبير الذي قبل الخاصية، وليس الخاصية نفسها. تحقق من الأسباب الخمسة المعتادة – قراءة البيانات غير المتزامنة في وقت مبكر جدًا، أو شكل واجهة برمجة التطبيقات غير المتطابق، أوfind لا يطابق شيئًا، ويهدم كائنًا غائبًا، ويضيعthis ملزم. ثم امنع التكرار من خلال التسلسل الاختياري حيث تكون القيم اختيارية حقًا، TypeScript معstrictNullChecksوالتحقق من صحة المخطط عند كل حدود تدخل فيها البيانات الخارجية إلى نظامك.
🔗 Share this article
✍️ Leave a Comment