X

Отладка и устранение распространённых ошибок в JavaScript

Временами работа над кодом JavaScript заставляет чувствовать себя выдохшимся и измождённым, поэтому некоторые подсказки по отладке никогда не будут лишними. На примерах из песен мы постараемся разобрать типичные ошибки в коде на JS и способы, которыми их можно найти и устранить.

Свойство не определено

let girl = {
    name: "Lucky",
    location: "Hollywood",
    profession: "star",
    thingsMissingInHerLife: true,
    lovely: true,
    cry: function() {
        return "cry, cry, cries in her lonely heart"
    }
}

console.log(girl.named.lucky)

Этот код выдаёт ошибку «Uncaught TypeError: Cannot read property ‘lucky’ of undefined». Дело в том, что объект girl не имеет свойства named, хотя у него есть свойство name. Поскольку свойство girl.named не определено, мы не можем получить к нему доступ, то есть оно просто не существует. Если мы заменим girl.named.lucky на girl.name, то код вернёт нам «Lucky».

Свойство — некоторое значение, привязанное к объекту JavaScript. Почитать больше об объектах можно здесь (статья на английском языке).

Отладка ошибок TypeError

Ошибки типа TypeError появляются, когда вы пытаетесь выполнить действия с данными, которые не соответствуют нужному типу, например применяете .bold() к числу, запрашиваете свойство undefined или пытаетесь вызвать как функцию что-то, не являющееся функцией. Например, вы увидите такую ошибку, если вызовете girl(), поскольку это объект, а не функция. В последнем случае вы получите «Uncaught TypeError: yourVariable.bold is not a function» и «girl is not a function».

Для отладки этих ошибок надо разобраться с переменными. Что такое girl? И что такое girl.named? Вы можете понять это изучая код, выводя переменные с помощью console.log, используя команду debugger или просто напечатав имя переменной в консоли. Удостоверьтесь, что вы можете манипулировать содержащимся в переменной типом данных. Если тип данных не подходит, модифицируйте его нужным образом, добавьте условие или блок try..catch, чтобы контролировать выполнение операции, или используйте эту операцию на другом объекте.

Переполнение стека

Если верить авторам песни «Baby One More Time», слово «hit» в строчке «Hit me baby, one more time» означает «позвони», то есть Бритни хочет, чтобы её бывший позвонил ей ещё раз. Это, возможно, приведёт к ещё большему количеству звонков в будущем. По сути это рекурсия, которая может вызвать ошибку в случае переполнения стека вызовов.

Конкретные сообщения об ошибке зависят от браузера, но выглядят они примерно так:

Error: Out of stack space (Edge)
InternalError: too much recursion (Firefox)
RangeError: Maximum call stack size exceeded (Chrome)

Переполнение стека может произойти, если в рекурсии не предусмотрен базовый случай или если код никогда не обращается к этому случаю.

function oneMoreTime(stillBelieve=true, loneliness=0) {
    if (!stillBelieve && loneliness < 0) return
    loneliness++
    return oneMoreTime(stillBelieve, loneliness)
}

В показанной выше функции stillBelieve никогда не примет значение false, и поэтому мы раз за разом будем вызывать oneMoreTime, увеличивая одиночество, и никогда не завершим выполнение функции.

Если же Бритни решит положиться на своих друзей, это уменьшит её одиночество, она перестанет верить, что можно вернуть отношения, и не будет больше ждать звонка от бывшего партнёра.

function oneMoreTime(stillBelieve=true, loneliness=0) {
    if (!stillBelieve && loneliness < 0) return
    loneliness--
    stillBelieve = false
    return oneMoreTime(stillBelieve, loneliness)
}

Есть похожие случаи с бесконечными циклами, когда система не выдаёт сообщение об ошибке, но вместо этого страница, на которой исполняется код, зависает. Это происходит в случае цикла while без условия завершения.

let worldEnded = false

while (worldEnded !== true) {
  console.log("Keep on dancin' till the world ends")
}

Исправить это можно примерно так же, как и предыдущий пример.

let worldEnded = false

while (worldEnded !== true) {
  console.log("Keep on dancin' till the world ends")
  worldEnded = true
}

Отладка бесконечных циклов и рекурсий

Для начала, если возникла проблема с бесконечным циклом, закройте вкладку, если вы пользуетесь Chrome или Edge, или окно браузера, если у вас Firefox. Затем просмотрите код: есть ли там что-то, что создаёт бесконечный цикл или рекурсию. Если ничего не обнаружили — добавьте в цикл или функцию команду debugger и проверьте значение переменных на нескольких начальных итерациях. Если они не соответствуют ожидаемым, вы это обнаружите.

В приведённом выше примере стоило бы добавить debugger самой первой строкой функции или цикла. Затем нужно открыть отладочную вкладку в Chrome и изучить переменные в Scope. С помощью кнопки «next» можно проследить, как они меняются с каждой итерацией. Обычно это помогает найти решение проблемы.

Здесь можно найти руководство на английском языке по отладке с помощью Chrome’s DevTools, а здесь — для Firefox.

Ошибка синтаксиса

SyntaxError — вероятно самая распространённая разновидность ошибок в JavaScript. Эти ошибки возникают, если вы не соблюдаете правила синтаксиса языка. Копируя посыл песни Бритни «Everytime», JavaScript говорит отсутствующим скобкам и кавычкам: «Вы нужны мне, крошки».

Соответствующие расширения текстового редактора помогут избежать ошибок. Bracket Pair Colorizer размечает скобки в коде разными цветами, а Prettier или другой инструмент статического анализа кода поможет быстро найти ошибки. Постарайтесь придерживаться правильной разметки и делайте блоки кода как можно короче и с минимальной вложенностью. Такой подход сильно облегчает отладку.

Теперь, вооружившись новыми навыками отладки, вы станете немного сильнее в JavaScript, чем были вчера.

Перевод статьи Oops, I did it again: A guide to debugging common JavaScript errors

Также рекомендуем:

Рубрика: Переводы
Темы: JavaScriptДля начинающихОтладка