Ошибка JavaScript – TypeError: null is not an object

Admin JavaScript, JavaScript Errors

Разбор ошибки на самом простом примере из практического пособия по изучению программирования на JavaScript.

При работе с JavaScript можно столкнуться с такой ошибкой:

0 TypeError: null is not an object (evaluating 'myHeading.textContent = 'Hello world!'')

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

Например, в этом коде:

var myHeading = document.querySelector('h1');
myHeading.textContent = 'Hello world!';

Используется отсылка к структуре h1. Если тега h1 в документе нет, то будет возникать соответствующая ошибка:
TypeError: null is not an object

Также ошибка будет возникать и в том случае, если код JavaScript будет загружаться перед H1, а не после. Это опять же исходит из того, что JavaScript воздействует на уже загруженные элементами. А если они загружаются после кода, то влиять на них он не может, потому что ещё не «видит».

Таким образом, если возникает ошибка TypeError: null is not an object смотрите какого объекта в структуре документа нет. Возможно перед JavaScript-ом не хватает простых div:

"<div></div>"

Если вам пригодилась информация, вы можете поблагодарить автора сайта символическим пожертвованием:

Комментарии к статье “Ошибка JavaScript – TypeError: null is not an object” (5)

  • Аватар
    Алекс
    24.05.2020 в 14:44

    Идея: низкоуровневые ошибки! Почему в Javascript нет низкоуровневых ошибок (Warning/Notice), как в PHP? Можно просто выбрасывать предупреждение:

    Warning: null is not an object

    или

    Warning: Cannot set property "..." of null

    Метод

    document.querySelector();

    не должен тихо возвращать null. Можно выбрасывать замечание

    Notice: DOM element "selector" not found

    и после него возвращать null.

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

    Пример: некорректные математические операции.

    3 * "string";

    должно выбросить предупреждение или замечание:

    A non-numeric value encountered

    а уже потом вернуть NaN. Должен быть предусмотрен отдельный оператор конкатенации строк, использование «+» должно приводить к низкоуровневой ошибке.

    Другие примеры.

    Деление на нуль должно генерировать замечание

    Notice: Division by zero

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

    Использование неитерируемого объекта в цикле for…of должно выбрасывать предупреждение вместо исключения.

    Методы, работающие с DOM, должны выбрасывать предупреждения вместо DOMException.

    Вывод напрямую массива или объекта в document должно сгенерировать замечания или предупреждения:

    Array to string conversion
    Object to string conversion

    Должна быть предусмотрена низкоуровневая ошибка Deprecated.

    И это далеко не все случаи, учитывая, что ECMAScript продолжает развиваться.

    Нужна функция типа PHP функции trigger_error(), выбрасывающая низкоуровневые ошибки, нужны предопределенные константы E_NOTICE, E_WARNING и E_DEPRECATED, а также константы E_CONSOLE и E_DOCUMENT, определяющие, куда выводить сообщение или предупреждение.

    Например:

    window.triggerError("Caught error on code", E_WARNING, E_CONSOLE);

    Не будут лишними и синтаксические предупреждения (предупреждения парсинга), например, пропуск точки с запятой, использование зарезервированного слова или код после return.

    • Admin
      Admin
      Автор записи
      24.05.2020 в 17:23

      PHP может работать, если ошибки не fatal. JavaScript устроен иначе. Почти любая ошибка сломает дальнейший код. Так исторически сложилось, не думаю, что это сегодня можно изменить.

      Что касается:

      3 * "string";

      есть TypeScript и надстройки над JavaScript, которые делают строгую типизацию в JS.

      • Аватар
        Алекс
        24.05.2020 в 21:16

        В приведенных примерах бросается исключение. Можно просто не бросать исключение, а писать в консоль или в HTML-код страницы предупреждение и выполнять какое-то действие по умолчанию. При этом обработчик ошибок не будет считать сообщение ошибкой. Например, код:

        var obj = {data: null, foo: "bar"};
        console.log(obj.data.data);
        console.log(obj.baz.data);

        должен вывести в консоль null и undefined и два предупреждения:

        Warning: Cannot read property 'data' of null in...
        Warning: Cannot read property 'data' of undefined in...

        В PHP тоже постепенно заменяют Fatal error на исключения, которые сами по себе, если не отловить, Fatal error.
        В принципе, несложно написать код на языке C++ (или на каком написан движок для браузеров?), реализующий помимо исключения низкоуровневую ошибку, не трогая остальной код движка. Сами исключения никуда не денутся. Кстати, как устроен Javascript, в двух словах? Просто замена предлагается постепенная. Слишком уж странная логика ошибок у Javascript. Деление на ноль, некорректная математическая операция, вывод неопределенных значений в HTML, обращение к булеву значению как к объекту, вызов функции без аргументов не вызывает даже вывода предупреждающего сообщения, не говоря уж об ошибках.
        Система ошибок Javascript подчиняется каким-то стандартам (IEEE и т.д.)?
        TypeScript не рассматриваем, так как он пока не встроен в Javascript. Предлагаемые изменения нужно именно встроить.
        Кстати, в Chrome нашел баг: код

        document.createElement(null);

        не вызовет ошибки, а создаст DOM элемент null, разумеется, невалидный.

      • Аватар
        Алекс
        25.05.2020 в 23:46

        Изучил исходный код движка V8 на C++ — тёмный-тёмный лес. Совершенно непонятно, где происходит выбрасывание ошибки типа «x is not defined» или «cannot read property of null». Поиск мало чего дает. Не нашёл исходного кода методов querySelector и других для работы с DOM. Не найдено исходного кода методов встроенных объектов. Где все это реализовано?

  • Аватар
    Алекс
    26.05.2020 в 12:34

    Изучил исходный код Chromium на Github и нашел такой код C++

      /*
      void некая_функция_уведомления(message) {
        сообщить_в_консоли("Notice: " + message);
      }
      void некая_функция_предупреждения(message) {
        предупредить_в_консоли("Warning: " + message);
        вывести_в_HTML("<br /><b>Warning</b>: " + message + "<br />");
      }
      */
     // ...
     if (selectors.IsEmpty()) {
       // вместо этого кода
        exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
                                          "The provided selector is empty.");
       // написать это:
       /*
         некая_функция_предупреждения("The provided selector is empty.");
       */
        return nullptr;
      }
      // ...
      CSSSelectorList selector_list = CSSParser::ParseSelector(
          MakeGarbageCollected<CSSParserContext>(
              document, document.BaseURL(), true /* origin_clean */,
              document.GetReferrerPolicy(), WTF::TextEncoding(),
              CSSParserContext::kSnapshotProfile),
          nullptr, selectors);

      if (!selector_list.First()) {
        // сюда вместо этого кода написать вывод предупреждения
        exception_state.ThrowDOMException(
            DOMExceptionCode::kSyntaxError,
            "'" + selectors + "' is not a valid selector.");
        /*
          некая_функция_предупреждения("'" + selectors + "' is not a valid selector.");
        */
        return nullptr;
      }

    И еще, если я правильно понял, код, где возвращается элемент или null:

    Element* SelectorQuery::Closest(Element& target_element) const {
      QUERY_STATS_RESET();
      if (selectors_.IsEmpty())
        return nullptr;
      if (needs_updated_distribution_)
        target_element.UpdateDistributionForFlatTreeTraversal();

      for (Element* current_element = &target_element; current_element;
           current_element = current_element->parentElement()) {
        if (SelectorListMatches(target_element, *current_element))
          return current_element;
      }
      // Здесь должно быть уведомление
      /*
       некая_функция_уведомления("DOM element '" + selectors + "' not found.");
      */
      return nullptr;
    }

    Думаю, что хоть вы в C++ и не разбираетесь особо, понятно. Кстати, раз уж пошла такая тема, то напишете статью про распространенные ошибки в Javascript с объяснениями? Заранее спасибо.

Добавить комментарий

Напишите свой комментарий, если вам есть что добавить/поправить/спросить по теме текущей статьи:
"Ошибка JavaScript – TypeError: null is not an object"