Ситуация: мы пишем на JavaScript конструктор профилей кошек. Для этого сначала создаём базовый объект с предопределёнными свойствами породы, окраса и клички, а затем добавляем новый — с изменёнными свойствами:
// базовый класс со значениями по умолчанию
function Cat() {
this.breed = "British Shorthair";
this.color = "чёрный";
this.name = "Даромир";
return this;
}
// метод установки имени
Cat.prototype.name = function (name) {
this.name = name;
return this;
};
// создаём новый объект и указываем для него новые значения
const myNewCat = new Cat();
myNewCat.breed ("Scottish Straight");
myNewCat.color ("белый");
myNewCat.name("Бернадетт");
// выводим профиль кота
console.log(myNewCat);
Но при запуске этого кода получаем ошибку:
❌ TypeError: myNewCat.breed is not a function
Странно, почему так, мы ведь просто меняем значения по умолчанию на свои?
Что это значит: мы попытались вызвать функцию, которая на самом деле функцией не является.
Когда встречается: ошибка "x" is not a function
может возникать в разных ситуациях. Например, программист забыл объявить функцию, но пытается её использовать; разработчик написал метод в локальной зоне видимости скрипта и пытается использовать её в глобальной; или же просто по невнимательности допустил опечатку в вызове функции — такое тоже часто случается.
Что делать с ошибкой "x" is not a function
Смотрите, что у нас было в примере: мы объявили свойства в классе, которые по своей сути — обычные строки:
this.breed = "British Shorthair";
this.color = "чёрный";
А дальше мы вместо того, чтобы присваивать им значения как обычным строковым переменным, зачем-то пытаемся использовать их как функции:
myNewCat.breed ("Scottish Straight");
myNewCat.color ("белый");
Не надо так.
Вторая ошибка — то, что мы создали свойство и метод в классе с одним и тем же именем — name
. В итоге скрипту непонятно, что именно мы хотим: вызвать функцию или поменять значение свойства? Чтобы это исправить, поменяем название свойства в классе и в методе:
Было в классе:
this.name = "Даромир";
Стало в классе:
this.catname = "Даромир";
Было в методе:
Cat.prototype.name = function (name) {
this.name = name;
return this;
};
Стало в методе:
Cat.prototype.name = function (name) {
this.catname = name;
return this;
};
Теперь, когда мы нашли и исправили все ошибки, у нас уже не возникает фантомных функций, с которыми JavaScript не знает что делать:
function Cat() {
this.breed = "British Shorthair";
this.color = "чёрный";
this.catname = "Даромир";
return this;
}
// метод установки имени
Cat.prototype.name = function (name) {
this.catname = name;
return this;
};
// создаём новый объект и указываем для него новые значения
const myNewCat = new Cat();
myNewCat.breed = "Scottish Straight";
myNewCat.color = "белый";
myNewCat.name("Бернадетт");
// выводим профиль кота
console.log(myNewCat);
Теперь разберём другие возможные причины ошибки "x" is not a function
.
Опечатка в вызове функции
Часто причиной ошибки "x" is not a function
оказывается обычная опечатка в названии метода. Нужно проверить правильность написания кода:
// такое написание вызовет ошибку
const x = document.getCatByID("foo");
// правильное написание
const x = document.getCatById("foo");
Отсутствует библиотека сценариев
Это тоже очень простая и частая ошибка, и для её исправления достаточно подключить библиотеку. Например, так импортируется jQuery:
Свойство вызывается как функция
Бывает так, что в объекте ожидалось, что что-то будет методом, а не просто строкой, но его сделали свойством. Тогда попытка вызова свойства как функции приведёт к ошибке:
let cat = {
name: "Даромир",
age: 2
};
cat.name();
Вместо того чтобы делать name строковым значением, нужно сделать его функцией, тогда ошибка перестанет возникать:
let cat = {
name: function() {
return "Даромир";
},
age: 2
};
Объект не содержит функцию
Ошибка может быть вызвана тем, что функция вызывается для объекта, который на самом деле не содержит функцию:
let cat = {
brand: "British Shorthair",
gender: "male"
};
cat.play();
Чтобы исправить ошибку, нужно проверить, что вызывается существующая функция, или добавить такую функцию в объект:
let cat = {
brand: "British Shorthair",
gender: "male",
play: function() {
console.log("Коть играет!");
}
};
cat.play();
Функция вызвана не для того объекта
Некоторые функции обратного вызова работают только с определёнными объектами. Например, метод map
используется только для массивов и не работает для обычных объектов с ключами:
const obj = { a: 4, b: 8, c: 15, d: 16, e: 23, f: 42 };
obj.map(function (num) {
return num * 2;
});
Чтобы ошибки не было, нужно использовать массив:
const numbers = [4, 8, 15, 16, 23, 43];
numbers.map(function (num) {
return num * 2;
});
Другой похожий пример — когда мы с помощью функции toUpperCase ()
пытаемся перевести в верхний регистр массив, а не строку. Разобрали эту ошибку в отдельной статье.
Как проверить тип функции
Проверить тип данных можно с помощью оператора typeof
:
if (typeof myObject.myMethod === 'function') {
myObject.myMethod();
} else {
console.error('myMethod — не функция');
}