- Yerleşik hata tiplerini (
TypeError,ReferenceError,RangeError,SyntaxError) ve genel nedenlerini tanımak - Kendi hata sınıflarını oluşturmak,
causeeklemek ve hataları, asenkron kod dahil, tipine göre işlemek - Bir yığın izini okumak ve kesme noktaları,
debuggerve konsol metotlarıyla hata ayıklamak
Bir kullanıcı yazıyor: “Düğme hiçbir şey yapmıyor.” Ekranda hiçbir işaret yok, ama konsolda kırmızı bir satır var: Chrome'da TypeError: Cannot read properties of undefined (reading 'price') ve altında dosya adlarıyla sayılar. Yeni başlayan için bu gürültüdür, bir profesyonel için ise doğrudan hataya götüren bir haritadır. Bu derste o haritayı okumayı ve kendi hatalarını doğru tasarlamayı öğreneceksin.
Yerleşik hata tipleri
| Tip | Genel neden | Örnek |
|---|---|---|
TypeError | yanlış tipte bir değerle işlem: fonksiyon olmayanı çağırmak, undefined/null'un özelliğini okumak | null.name, (42)() |
ReferenceError | var olmayan (ya da TDZ'deki) bir değişken | console.log(missing) |
RangeError | izin verilen aralığın dışında bir sayı | new Array(-1) |
SyntaxError | ayrıştırılamayan kod ya da JSON | JSON.parse('{bad}') |
const attempts = [
() => null.name,
() => missingVariable,
() => new Array(-1),
() => JSON.parse('{bad json}'),
() => (42)(),
];
for (const attempt of attempts) {
try {
attempt();
} catch (error) {
console.log(error.name, '|', error instanceof Error);
}
}▸ Beklenen çıktı
TypeError | true ReferenceError | true RangeError | true SyntaxError | true TypeError | true
Kendi hataların ve cause
throw her değeri fırlatabilir, ama her zaman bir Error nesnesi fırlat; yığın izi yalnızca onda vardır. İyi bir kural: yalnızca işleyebildiğin hataları yakala, gerisini yeniden fırlat (throw error). Programının hatalarını birbirinden ayırmak için Error'dan türeyen bir sınıf hiyerarşisi kur; böylece instanceof ile her türe uygun tepki verebilirsin.
class AppError extends Error {
constructor(message, options) {
super(message, options);
this.name = this.constructor.name;
}
}
class ValidationError extends AppError {}
class NotFoundError extends AppError {}
function findUser(users, id) {
if (!Number.isInteger(id)) throw new ValidationError(`Bad id: ${id}`);
const user = users.find((u) => u.id === id);
if (!user) throw new NotFoundError(`User ${id} not found`);
return user;
}
const users = [{ id: 1, name: 'Aysel' }];
for (const id of [1, 'x', 7]) {
try {
console.log(findUser(users, id).name);
} catch (error) {
if (error instanceof ValidationError) console.log('400', error.message);
else if (error instanceof NotFoundError) console.log('404', error.message);
else throw error;
}
}▸ Beklenen çıktı
Aysel 400 Bad id: x 404 User 7 not found
this.constructor.name, her alt sınıfa otomatik olarak doğru adı verir. 400 ve 404 birer HTTP durum kodudur; API dersinde onlara döneceğiz.Alt düzeydeki bir hatayı yakalayıp daha anlaşılır bir hata fırlattığında orijinalini **cause** (ES2022) özelliğinde sakla. Böylece kullanıcı net bir mesaj görür, geliştirici de gerçek nedeni kaybetmez.
function loadSettings(text) {
try {
return JSON.parse(text);
} catch (error) {
throw new Error('Settings file is broken', { cause: error });
}
}
try {
loadSettings('{ theme: dark }');
} catch (error) {
console.log(error.message);
console.log('Caused by:', error.cause.name);
console.log(error.cause instanceof SyntaxError);
}▸ Beklenen çıktı
Settings file is broken Caused by: SyntaxError true
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function saveScore(score) {
await wait(100);
if (score < 0) throw new RangeError('Score cannot be negative');
return 'saved';
}
try {
console.log(await saveScore(10));
console.log(await saveScore(-5));
} catch (error) {
console.log(`${error.name}: ${error.message}`);
}
const result = await saveScore(-1).catch((error) => `fallback (${error.message})`);
console.log(result);▸ Beklenen çıktı
saved RangeError: Score cannot be negative fallback (Score cannot be negative)
Yığın izini okumak
Yığın izi (stack trace), hatanın oluştuğu andaki çağrı zincirini gösterir; en yenisi en üsttedir. İlk satır hatanın adı ve mesajıdır, sonraki satırlar at fonksiyon (dosya:satır:sütun) biçimindedir. Aşağıdaki cart.js dosyasında ikinci ürünün product özelliği yok. Node.js'in yazdırdığı iz şöyle (klasör yolları kısaltıldı, Node'un iç satırları çıkarıldı):
// cart.js
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.product.price * item.qty, 0);
}
function renderCart(cart) {
return calculateTotal(cart.items);
}
renderCart({ items: [{ product: { price: 2 }, qty: 1 }, { qty: 3 }] });TypeError: Cannot read properties of undefined (reading 'price')
at cart.js:3:57
at Array.reduce (<anonymous>)
at calculateTotal (cart.js:3:16)
at renderCart (cart.js:6:10)
at Object.<anonymous> (cart.js:8:1)Hata ayıklama araçları
- 1Hatayı yeniden üret
Hataya yol açan kesin adımları bul.
- 2Bir kesme noktası koy
DevTools ›
Sourcespanelinde bir satır numarasına tıkla ya da kodadebugger;yaz; DevTools açıkken çalışma orada durur. - 3Değerleri incele
Scopebölümünde değişkenlere bak, fareyi değerlerin üzerine getir,Watch'a ifadeler ekle. - 4Adım adım ilerle
Satır satır ilerle, bir fonksiyonun içine gir ya da ondan çık.
- 5Düzelt ve doğrula
Düzeltmeden sonra aynı adımları tekrar uygula.
Konsolun log dışında da kullanışlı metotları vardır. Bu sayfadaki çalıştırıcı yalnızca console.log'u gösterir; bu yüzden örneği tarayıcı konsolunda ya da Node.js'te çalıştır. Aşağıdaki çıktı Node.js'ten; sort için ölçülen süre her çalıştırmada farklıdır.
const students = [
{ name: 'Aysel', score: 92 },
{ name: 'Murad', score: 78 },
];
console.table(students);
console.group('Checkout');
console.log('items: 3');
console.warn('coupon expired');
console.groupEnd();
console.count('click');
console.count('click');
console.assert(students.length > 5, 'Expected more than 5 students');
console.time('sort');
students.sort((a, b) => b.score - a.score);
console.timeEnd('sort');┌─────────┬─────────┬───────┐ │ (index) │ name │ score │ ├─────────┼─────────┼───────┤ │ 0 │ 'Aysel' │ 92 │ │ 1 │ 'Murad' │ 78 │ └─────────┴─────────┴───────┘ Checkout items: 3 coupon expired click: 1 click: 2 Assertion failed: Expected more than 5 students sort: 0.027ms
ValidationError sınıfını tamamla (name değeri 'ValidationError' olmalı) ve parseAge(text) fonksiyonunu yaz. Metin tam sayı değilse Not a whole number: <text>, 0–120 aralığının dışındaysa Out of range: <age> mesajlı bir ValidationError fırlat; aksi hâlde yaşı döndür.
class ValidationError extends Error {
// set this.name in the constructor
}
function parseAge(text) {
// Number(text) must be an integer from 0 to 120
}
for (const input of ['16', 'abc', '130', '42']) {
try {
console.log('Age:', parseAge(input));
} catch (error) {
if (error instanceof ValidationError) {
console.log(`${error.name}: ${error.message}`);
} else {
throw error;
}
}
}▸ Beklenen çıktı
Age: 16 ValidationError: Not a whole number: abc ValidationError: Out of range: 130 Age: 42
retry(fn, times) fonksiyonunu yaz: fn'i başarılı olana kadar en fazla times kez çağırsın ve her başarısızlıktan sonra Retrying after: <mesaj> yazdırsın. Tüm denemeler başarısız olursa son hatayı cause içinde saklayan, All <times> attempts failed mesajlı bir hata fırlatsın.
function createFlakyTask(failuresBeforeSuccess) {
let calls = 0;
return () => {
calls++;
if (calls <= failuresBeforeSuccess) throw new Error(`Attempt ${calls} failed`);
return `Success on attempt ${calls}`;
};
}
function retry(fn, times) {
// your code here
}
console.log(retry(createFlakyTask(2), 3));
try {
retry(createFlakyTask(5), 3);
} catch (error) {
console.log(error.message, '| cause:', error.cause.message);
}▸ Beklenen çıktı
Retrying after: Attempt 1 failed Retrying after: Attempt 2 failed Success on attempt 3 Retrying after: Attempt 1 failed Retrying after: Attempt 2 failed Retrying after: Attempt 3 failed All 3 attempts failed | cause: Attempt 3 failed
Önemli noktalar
TypeErroryanlış tip ya daundefined,ReferenceErrorbilinmeyen değişken,RangeErroraralık dışı değer,SyntaxErrorise ayrıştırılamayan kod ya da JSON demektir.- Mesaj metnini değil,
error.name'i ya dainstanceof'u kontrol et; mesajlar tarayıcıya göre değişir. - Kendi hata sınıfların ve
cause, hataları anlamlı kılar ve asıl nedeni korur. - Asenkron bir hata yalnızca
tryiçindekiawaitya da.catch()ile yakalanır. - Yığın izini kendi dosyanın geçtiği ilk satırdan oku; tahmin etmek yerine kesme noktaları,
debuggerve konsol metotlarını kullan.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
const user = null; user.length; hangi hatayı fırlatır?