Суть Прочитай stack trace и короткие сниппеты, затем классифицируй каждый сбой: какая строка бросила, defined error это или undefined behaviour, и где живёт настоящая причина.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min
Сбой читается в двух местах: код, который выполнился, и trace, который напечатал рантайм. Для каждого сниппета ниже делай то, что инженер делает первым — найди throw site, назови вид сбоя и реши, где живёт настоящая причина.
Цель
Потренируй цикл чтения, к которому вёл юнит: разбирай stack trace сверху вниз, чтобы найти throw site, классифицируй сбой как defined error или undefined behaviour и отделяй, где exception всплыл, от того, где реально сидит его причина.
Сниппет 1 — прочитай trace
Error: Cannot read properties of undefined (reading 'name') at formatLabel (render.ts:14) at renderRow (render.ts:31) at renderTable (render.ts:48) at main (app.ts:9)
Викторина
Completed
Читая этот trace сверху вниз, какое утверждение верно?
Heads-up Нижняя строка — точка входа: она почти в каждом trace и почти никогда не причина. Throw site — верхняя строка, formatLabel в render.ts:14.
Heads-up Trace — не список функций файла. Это лишь фреймы, активные на стеке в момент throw — цепочка main → renderTable → renderRow → formatLabel.
Heads-up Throw site — всегда верхняя строка. renderRow стоит ниже formatLabel, то есть renderRow ждал на строке 31 на своём вызове formatLabel — он не бросал.
Сниппет 2 — классифицируй сбой
function loadUser(record) { return record.profile.name.toUpperCase();}loadUser({ profile: null }); // profile is null, not an object
Викторина
Completed
record.profile равен null, поэтому код читает .name у null. Какой это вид сбоя в JavaScript и как ты о нём узнаешь?
Heads-up Чтение свойства у null — defined error в JavaScript: оно поднимает exception. Undefined behaviour — тихий случай без поднятия ошибки, а это громкий, отрепортованный случай.
Heads-up null.name не возвращает undefined; чтение свойства у null поднимает TypeError. (Чтение отсутствующего свойства у объекта дало бы undefined, но null — не объект.)
Heads-up Это детерминировано и определено: то же чтение у null всегда поднимает тот же exception. В языке, который проверяет этот случай, исхода с мусорными битами нет.
Сниппет 3 — выход за границы, два языка
prices = [10, 20, 30] // valid indices 0, 1, 2read prices[5] // index 5 — two past the end
Викторина
Completed
Одно и то же чтение за границей выполняется в языке с проверкой границ и в низкоуровневом языке без проверки. Чем различаются исходы?
Heads-up Только язык с проверкой границ поднимает exception. Низкоуровневый язык без проверки не делает её — он читает ячейку за границей и возвращает мусор вообще без ошибки.
Heads-up undefined — это конкретный определённый результат JavaScript. У низкоуровневого языка без проверки такой гарантии нет — он читает любые биты по вычисленному адресу.
Heads-up То, что индекс невалиден, — в этом вся суть. Язык с проверкой границ обнаруживает это и бросает; язык без проверки игнорирует и читает память, которую не должен.
Сниппет 4 — throw site не есть причина
function parseAge(text) { const n = Number(text); if (Number.isNaN(n)) throw new Error("not a number: " + text); return n;}function loadProfile(raw) { return { age: parseAge(raw.age) }; // raw.age came from upstream}// raw.age is "thirty" — never validated before reaching here
Викторина
Completed
Trace упирается в parseAge ('not a number: thirty'). Гипотеза при debugging должна отделить, где exception всплыл, от того, где живёт причина. Какое прочтение верно?
Heads-up parseAge делает свою работу: обнаруживает плохой вход и громко его репортует. Удаление throw превратило бы громкий, определённый сбой в тихий — худший исход. Дефект — непровалидированное 'thirty' выше.
Heads-up Верхняя строка — где error всплыл, не всегда где живёт причина. Здесь вызывающий передал плохие данные; рассуждение идёт по цепочке к шагу выше, где состояние впервые пошло не так.
Heads-up Бросать на плохом входе — корректное поведение, но сам плохой вход — дефект. Суть юнита — продолжать рассуждение за throw site до шага, который первым разошёлся.
Итог
Любой сбой читается в коде и trace: trace разбирается сверху вниз, верхняя строка — throw site, нижняя — лишь точка входа; чтение свойства у null — defined error, который громко поднимается, а непроверенное чтение за границей — undefined behaviour, молча возвращающее мусор; и throw site — где error всплыл, не всегда где живёт причина. Классифицируй сбой, найди, где он всплыл, затем рассуждай вниз по цепочке к шагу, который первым пошёл не так.