Вы пишете код, всё кажется логичным, но консоль вдруг выдаёт холодное и немного унизительное сообщение: \"Uncaught TypeError: ... is not a function\". Сердце замирает, а мысль \"но это же функция!\" сталкивается с непреклонной реальностью интерпретатора. Эта ошибка — один из самых частых \"камней преткновения\" для разработчиков, работающих с JavaScript. Но за её сухой формулировкой скрывается целый мир нюансов, понимание которых отделяет новичка от уверенного программиста.
\n\nЧто на самом деле говорит вам браузер?
\nОшибка TypeError: X is not a function возникает, когда JavaScript-движок пытается вызвать что-то как функцию, но это \"что-то\" на момент вызова функцией не является. Ключевое слово здесь — \"на момент вызова\". Ваша переменная может быть объявлена как функция, но к моменту исполнения проблемной строки её значение могло измениться или оказаться недоступным.
Ошибка относится к типу TypeError, что указывает на несоответствие типа данных ожидаемому. Это ошибка времени выполнения (Runtime Error), которая возникает, когда код уже исполняется.
Типичные причины появления ошибки
\nДавайте систематизируем основные сценарии, которые приводят к этой досадной проблеме.
\n\n1. Опечатка в имени функции или метода
\nСамая простая и обидная причина. JavaScript — регистрозависимый язык.
\nconst message = 'Hello';\nconsole.log(message.toUppercase()); // TypeError: message.toUppercase is not a function\n// Правильно: toUpperCase()\n\n2. Попытка вызвать как функцию то, что функцией не является
\nЧасто случается при работе с DOM-элементами, массивами или объектами, когда вы ошибочно полагаете, что имеете дело с функцией.
\nlet element = document.getElementById('myButton');\nelement.click(); // Это работает, если элемент найден\nlet elements = document.querySelectorAll('.buttons');\nelements[0].click(); // Работает\nelements.click(); // TypeError: elements.click is not a function\n// querySelectorAll возвращает NodeList, а не одиночный элемент\n\n3. Функция не определена в текущей области видимости
\nВы вызываете функцию до её объявления (в случае с const и let) или она просто не существует в доступном пространстве имён.
// Пример с областью видимости\nif (true) {\n const innerFunc = () => console.log('Inside!');\n}\ninnerFunc(); // ReferenceError, а затем может привести к TypeError\n\n// Пример с порядком исполнения\nmyFunction(); // TypeError, если myFunction — const/let\nconst myFunction = () => { console.log('Too late!'); };\n\n4. Значение переменной было перезаписано
\nИзначально в переменной была функция, но позже в неё записали другое значение (число, строку, null, undefined).
\nlet handler = () => { console.log('Click!'); };\n// ... много кода ...\nhandler = null;\n// ... ещё код ...\nhandler(); // TypeError: handler is not a function\n\n5. Проблемы с контекстом (this)
\nКлассическая проблема при работе с методами объектов и обработчиками событий. Метод теряет привязку к своему объекту.
\nconst user = {\n name: 'Alice',\n greet() { console.log(`Hello, ${this.name}`); }\n};\nconst greetFunc = user.greet;\ngreetFunc(); // TypeError (в строгом режиме) или undefined\n// this стал равен undefined или window, и метод \"сломался\"\n\nМетодика отладки и поиска причины
\n- \n
- Читайте сообщение ошибки внимательно. Браузер укажет номер строки и файл. Часто этого уже достаточно. \n
- Используйте console.log() или debugger. Выведите в консоль значение переменной, которую пытаетесь вызвать, прямо перед проблемной строкой.
console.log(typeof myVar, myVar);Покажет тип и текущее значение. \n - Проверьте цепочку вызовов (Call Stack) в инструментах разработчика. Это поможет понять, откуда пришло ошибочное значение. \n
- Убедитесь, что скрипт загружен. Если функция определена в отдельном файле, проверьте, что он подключён и нет ошибок сети. \n
Использование строгого режима 'use strict'; в начале файла или функции помогает выявлять многие ошибки, связанные с this и неявным созданием глобальных переменных, которые могут привести к \"is not a function\".
Как предотвратить ошибку? Профилактика лучше лечения
\n- \n
- Используйте TypeScript или JSDoc. Статическая проверка типов перехватит большинство таких ошибок на этапе написания кода. \n
- Проверяйте типы перед вызовом. Особенно для значений, пришедших извне (API, пользовательский ввод).\n
if (typeof callback === 'function') {\n callback();\n} else {\n // Обработка случая, когда callback — не функция\n}\n - Применяйте опциональную цепочку (Optional Chaining, ?.) для методов.\n
// Вместо obj.method()\nobj.method?.(); // Вызовется только если method существует и является функцией\n - Будьте осторожны с именами. Следите за регистром и используйте понятные, уникальные имена для функций. \n
- Инициализируйте переменные. Присваивайте переменным, предназначенным для хранения функций, значение
nullили функцию-заглушку по умолчанию. \n
FAQ: Часто задаваемые вопросы
\nВ чём разница между \"is not a function\" и \"is undefined\"?
\nis not a function означает, что по указанному имени что-то есть (не undefined), но это \"что-то\" нельзя вызвать. is undefined (ReferenceError) означает, что переменной с таким именем вообще не существует в доступной области видимости.
Почему ошибка возникает при вызове метода массива, например, map?
\nСкорее всего, вы вызываете map не на массиве, а на другом типе данных (например, на NodeList, объекте или null). Убедитесь, что ваша переменная действительно является массивом: Array.isArray(myVar).
Как быть, если функция импортируется из модуля?
\nПроверьте: 1) Правильность пути и имени экспорта в инструкции import. 2) Что экспорт с таким именем действительно существует в целевом модуле. 3) Что используется правильный синтаксис (например, для default export).
Ошибка появляется только в браузере пользователя, а у меня всё работает. В чём дело?
\nВероятные причины: 1) Кэш старого JS-файла у пользователя. 2) Разная версия API или данных, приходящих с сервера. 3) Разная поддержка JavaScript (например, если вы используете современный синтаксис, который не поддерживается в старом браузере). Используйте транспиляцию (Babel) и следите за полифилами.
\n\nМожно ли отловить эту ошибку в try...catch?
\nДа, безусловно. Все ошибки типа TypeError можно и нужно обрабатывать в блоке try...catch, если вы предполагаете возможность их возникновения (например, при работе с ненадёжными данными или сторонними библиотеками).
Понимание ошибки TypeError: ... is not a function — это не просто умение её починить. Это глубокое погружение в механику выполнения JavaScript, работу с типами, областями видимости и контекстом. Каждая такая ошибка делает вас на шаг ближе к написанию стабильного, предсказуемого и профессионального кода.