Ошибки в JavaScript и как их исправить

Автор оригинала: Jani Hartikainen
  • Перевод
JavaScript может быть кошмаром при отладке: некоторые ошибки, которые он выдает, могут быть очень трудны для понимания с первого взгляда, и выдаваемые номера строк также не всегда полезны. Разве не было бы полезно иметь список, глядя на который, можно понять смысл ошибок и как исправить их? Вот он!

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

Как читать ошибки?


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

Типичная ошибка из Chrome выглядит так:

Uncaught TypeError: undefined is not a function

Структура ошибки следующая:
  1. Uncaught TypeError: эта часть сообщения обычно не особо полезна. Uncaught значит, что ошибка не была перехвачена в catch, а TypeError — это название ошибки.
  2. undefined is not a function: это та самая часть про ошибку. В случае с сообщениями об ошибках, читать их нужно прямо буквально. Например, в этом случае, она значит то, что код попытался использовать значение undefined как функцию.

Другие webkit-браузеры, такие как Safari, выдают ошибки примерно в таком же формате, как и Chrome. Ошибки из Firefox похожи, но не всегда включают в себя первую часть, и последние версии Internet Explorer также выдают более простые ошибки, но в этом случае проще — не всегда значит лучше.

Теперь к самим ошибкам.

Uncaught TypeError: undefined is not a function


Связанные ошибки: number is not a function, object is not a function, string is not a function, Unhandled Error: ‘foo’ is not a function, Function Expected

Возникает при попытке вызова значения как функции, когда значение функцией не является. Например:

var foo = undefined;
foo();

Эта ошибка обычно возникает, если вы пытаетесь вызвать функцию для объекта, но опечатались в названии.

var x = document.getElementByID('foo');

Несуществующие свойства объекта по-умолчанию имеют значение undefined, что приводит к этой ошибке.

Другие вариации, такие как “number is not a function” возникают при попытке вызвать число, как будто оно является функцией.

Как исправить ошибку: убедитесь в корректности имени функции. Для этой ошибки, номер строки обычно указывает в правильное место.

Uncaught ReferenceError: Invalid left-hand side in assignment


Связанные ошибки: Uncaught exception: ReferenceError: Cannot assign to ‘functionCall()’, Uncaught exception: ReferenceError: Cannot assign to ‘this’

Вызвано попыткой присвоить значение тому, чему невозможно присвоить значение.

Наиболее частый пример этой ошибки — это условие в if:

if(doSomething() = 'somevalue')

В этом примере программист случайно использовал один знак равенства вместо двух. Выражение “left-hand side in assignment” относится к левой части знака равенства, а, как можно видеть в данном примере, левая часть содержит что-то, чему нельзя присвоить значение, что и приводит к ошибке.

Как исправить ошибку: убедитесь, что вы не пытаетесь присвоить значение результату функции или ключевому слову this.

Uncaught TypeError: Converting circular structure to JSON


Связанные ошибки: Uncaught exception: TypeError: JSON.stringify: Not an acyclic Object, TypeError: cyclic object value, Circular reference in value argument not supported

Всегда вызвано циклической ссылкой в объекте, которая потом передается в JSON.stringify.

var a = { };
var b = { a: a };
a.b = b;
JSON.stringify(a);

Так как a и b в примере выше имеют ссылки друг на друга, результирующий объект не может быть приведен к JSON.

Как исправить ошибку: удалите циклические ссылки, как в примере выше, из всех объектов, которые вы хотите сконвертировать в JSON.

Unexpected token ;


Связанные ошибки: Expected ), missing ) after argument list

Интерпретатор JavaScript что-то ожидал, но не обнаружил там этого. Обычно вызвано пропущенными фигурными, круглыми или квадратными скобками.

Токен в данной ошибке может быть разным — может быть написано “Unexpected token ]”, “Expected {” или что-то еще.

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

Ошибка с [ ] { } ( ) обычно вызвано несовпадающей парой. Проверьте, все ли ваши скобки имеют закрывающую пару. В этом случае, номер строки обычно указывает на что-то другое, а не на проблемный символ.

Unexpected / связано с регулярными выражениями. Номер строки для данного случая обычно правильный.

Unexpected; обычно вызвано символом; внутри литерала объекта или массива, или списка аргументов вызова функции. Номер строки обычно также будет верным для данного случая.

Uncaught SyntaxError: Unexpected token ILLEGAL


Связанные ошибки: Unterminated String Literal, Invalid Line Terminator

В строковом литерале пропущена закрывающая кавычка.

Как исправить ошибку: убедитесь, что все строки имеют правильные закрывающие кавычки.

Uncaught TypeError: Cannot read property ‘foo’ of null, Uncaught TypeError: Cannot read property ‘foo’ of undefined


Связанные ошибки: TypeError: someVal is null, Unable to get property ‘foo’ of undefined or null reference

Попытка прочитать null или undefined так, как будто это объект. Например:

var someVal = null;
console.log(someVal.foo);

Как исправить ошибку: обычно вызвано опечатками. Проверьте, все ли переменные, использованные рядом со строкой, указывающей на ошибку, правильно названы.

Uncaught TypeError: Cannot set property ‘foo’ of null, Uncaught TypeError: Cannot set property ‘foo’ of undefined


Связанные ошибки: TypeError: someVal is undefined, Unable to set property ‘foo’ of undefined or null reference

Попытка записать null или undefined так, как будто это объект. Например:

var someVal = null;
someVal.foo = 1;

Как исправить ошибку: это тоже обычно вызвано ошибками. Проверьте имена переменных рядом со строкой, указывающей на ошибку.

Uncaught RangeError: Maximum call stack size exceeded


Связанные ошибки: Uncaught exception: RangeError: Maximum recursion depth exceeded, too much recursion, Stack overflow

Обычно вызвано неправильно программной логикой, что приводит к бесконечному вызову рекурсивной функции.

Как исправить ошибку: проверьте рекурсивные функции на ошибки, которые могут вынудить их делать рекурсивные вызовы вечно.

Uncaught URIError: URI malformed


Связанные ошибки: URIError: malformed URI sequence

Вызвано некорректным вызовом decodeURIComponent.

Как исправить ошибку: убедитесь, что вызовы decodeURIComponent на строке ошибки получают корректные входные данные.

XMLHttpRequest cannot load some/url. No ‘Access-Control-Allow-Origin’ header is present on the requested resource


Связанные ошибки: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at some/url

Эта проблема всегда связана с использованием XMLHttpRequest.

Как исправить ошибку: убедитесь в корректности запрашиваемого URL и в том, что он удовлетворяет same-origin policy. Хороший способ найти проблемный код — посмотреть на URL в сообщении ошибки и найти его в своём коде.

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable


Связанные ошибки: InvalidStateError, DOMException code 11

Означает то, что код вызвал функцию, которую нельзя было вызывать в текущем состоянии. Обычно связано c XMLHttpRequest при попытке вызвать на нём функции до его готовности.

var xhr = new XMLHttpRequest();
xhr.setRequestHeader('Some-Header', 'val');

В данном случае вы получите ошибку потому, что функция setRequestHeader может быть вызвана только после вызова xhr.open.

Как исправить ошибку: посмотрите на код в строке, указывающей на ошибку, и убедитесь, что он вызывается в правильный момент или добавляет нужные вызовы до этого (как с xhr.open).

Заключение


JavaScript содержит в себе одни из самых бесполезных ошибок, которые я когда-либо видел, за исключением печально известной Expected T_PAAMAYIM_NEKUDOTAYIM в PHP. Большая ознакомленность с ошибками привносит больше ясности. Современные браузеры тоже помогают, так как больше не выдают абсолютно бесполезные ошибки, как это было раньше.

Какие самые непонятные ошибки вы встречали? Делитесь своими наблюдениями в комментариях.

P.S. Этот перевод можно улучшить, отправив PR здесь.
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 14

    0
    печально известной Expected T_PAAMAYIM_NEKUDOTAYIM
    Не буду оправдывать, но скажу, что ошибка с таким названием как минимум легко гуглится:)
      +7
      Эммм, простите, но мне кажется что тексты приведенных здесь ошибок абсолютно очевидно указывают на причину этих ошибок.
      Неужто увидев в консоли "Uncaught TypeError: Cannot set property ‘foo’ of null, Uncaught TypeError: Cannot set property ‘foo’ of undefined" вы будете чесать репу и делать что-то иное кроме как искать .foo или ['foo'] в строке указанной в стек-трейсе?
        +3
        Я довольно часто вижу, что за рубежом говорят: “Так классно, спасибо. Ты же еще и время на это потратил”. А в России: “Ой, это же каждый знает, всё итак понятно”.

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

        P.S. Все замечания по контенту можете отправлять в оригинал статьи, здесь только перевод.
          +3
          Ну хорошо-хорошо, некоторые не совсем очевидны, например «Unexpected token ILLEGAL» (хотя качественный редактор вам жирно и пестро пометит место, где у вас ILLEGAL прячется) :)
          Ну и да, новичкам это, разумеется, будет полезно и интересно
            +5
            Так классно, спасибо. Ты же еще и время на это потратил)
              0
              Я довольно часто вижу, что за рубежом говорят: “Так классно, спасибо. Ты же еще и время на это потратил”. А в России: “Ой, это же каждый знает, всё итак понятно”.

              В данном контексте я бы рассматривал эти фразы, как показатель компетентности среднего разработчика. Если на этом вашем западе хвалят такую статью, то я сильно сомневаюсь в профессионализме хвалящего. Ибо это такие основы, которые просто стыдно не знать.

              Другое дело, если бы были показаны типичные (или наоборот, нетипичные, но весьма занимательные) ошибки, когда ошибка в одном месте приводит к сообщению об ошибке в другом. А также как восстанавливать реальное положение ошибочного кода (вообще я сомневаюсь, что это возможно в такой постановке). Сам я зашел сюда только за этими советами, а их и нет — одна вода, «если забыли кавычку, поставьте кавычку, забыли скобку — поставьте скобку».

              P.S. Все замечания по контенту можете отправлять в оригинал статьи, здесь только перевод.

              Ну почему же. Если вы уже решились на перевод, то должны понимать его ценность. А если ценности нет никакой, то может ну его, этот перевод? И поискать что-нибудь покачественнее?
            –5
            все это замечательно работает пока вы не начинаете использовать jQuery. И вот тут разверзаются врата в ад
              +2
              Хорошо-хорошо, разверну мысль для тех, кто не понял. Когда вы используете jQuery, ошибка типа «Uncaught TypeError: undefined is not a function», которая произошла в недрах вашей функции, например, обработчика клика по ссылке/кнопке/итп будет показывать куда угодно, только не на вашу функцию. В принципе даже не рядом. Можно только догадаться, что последний раз ты менял там-то и возможно, где-то там что-то где-то не учтено или не там стоит запятая (на которые яваскрипту вообщем-то тоже положить и сообщение об ошибке тоже будет вести куда угодно, кроме вашей функции с ошибкой)
                –3
                гыгы, jquery, в основном, вешают на элементы DOM'а, а тут все просто и дебажить и прочее.
                  0
                  мое любимое: jquery плагин (слайдер картинок) на конкретной странице сайта падает внутри себя с сообщением про «undefined is not a function». Падает только на этой странице, при этом сам плагин годами успешно применяется и работает на куче сайтов без каких либо проблем. Причина? Другой скрипт подтянул извне другую версию jQuery и в итоге у нас на странице оказывается два jQuery разных версий. Причем сами-то функции jQuery данную ситуацию как-то ухитряются разруливать…

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

                  Отладка в консоли браузера — это боль.
                  +1
                  Ну, девтулзы хрома вам например покажут полный стек вызовов, и там вы найдете номер строки в вашем файле, с которой все началось
                    +1
                    А ещё там можно посмотреть откуда в коде был вызван http запрос на вкладке запросов.
                –1
                Вроде как для того, чтобы избегать большей части перечисленных ошибок придуманы различные IDE и расширения типа Typescript, а также принципы кодирования (как минимум не использовать однобуквенные идентификаторы без надобности).
                  +1
                  Cовсем недавно один инициативный человек из Новосибирска выступал с докладом на подобную тему.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое