Illegal invocation TypeError: Illegal invocation
вызывается при вызове setTimeout
с переменным обратным вызовом. Я читал, что это происходит, когда this
относится к другому объекту в обратном вызове и что для его решения используются функции bind
или стрелки. Однако не this
в моем обратном вызове.
Код выглядит следующим образом:
class AlarmService {
constructor(callback) {
this._alarms = {};
this.setTimeout = window.setTimeout;
this.clearTimeout = window.clearTimeout;
this._callback = callback || function () {};
}
create(alarmName, when, title, message) {
this._alarms[alarmName] = {
'title': title,
'message': message
};
this._alarms.timeout = this.setTimeout(this._callback, when - Date.now(),
this._alarms[alarmName]);
}
}
let alarms = new AlarmService(function (alarm) {
console.log('Alarm', alarm.name);
});
// Exception is thrown here
alarms.create('alarmName', Date.now() + 3000, 'Title', 'Message');
Обратите внимание, что я использую babel и es2015.
В примере кода функции setTimeout и clearTimeout вызывается с недопустимым контекстом (this
). О возможном исправлении является привязка к правильному контексту (window
):
constructor(callback) {
this._alarms = {};
this.setTimeout = window.setTimeout.bind(window);
this.clearTimeout = window.clearTimeout.bind(window);
this._callback = callback || function () {};
}
Обычно this
объект следует this
внутри функции, указывающей на объект слева от точки в вызове:
alerts.create(...) // inside create(), this === alerts
^
|___ "this"
Когда нет точки, зависит от того, является ли функция вызывающего абонента строгой:
var create = alerts.create
create() // this === Window or global
^
|_____ no dot
А также
'use strict'
var create = alerts.create
create() // this === undefined
^
|_____ no dot
Учитывая, что мы называем setTimeout
без точки, мы можем думать, что this
контекст не имеет значения. Но в браузерах он будет жаловаться, если вы назовете его точкой, или используйте вариант, который передает в качестве контекста нечто иное, чем окно.
Fire Fox:
Uncaught TypeError: незаконный вызов
Хром:
TypeError: 'setTimeout' вызывает объект, который не реализует окно интерфейса.
Другие предложили придерживаться обычного setTimeout(fn, timeout)
. Еще один способ - создать анонимную функцию:
this.setTimeout = (fn, timeout) => setTimeout(fn, timeout);
В вашем setTimeout
вызове this
нет, однако setTimeout
называется глобально.
Итак, this.setTimeout
должен быть setTimeout
class AlarmService {
constructor(callback) {
this._alarms = {};
this.setTimeout = window.setTimeout;
this.clearTimeout = window.clearTimeout;
this._callback = callback || function () {};
}
create(alarmName, when, title, message) {
this._alarms[alarmName] = {
'title': title,
'message': message
};
this._alarms.timeout = setTimeout(this._callback, when - Date.now(), this._alarms[alarmName]);
}
}
let alarms = new AlarmService(function (alarm) {
console.log('Alarm', alarm);
});
alarms.create('alarmName', Date.now() + 3000, 'Title', 'Message'); // Exception is thrown here
this
. Не имеет значения, что обратный вызов не относится кthis
. Проблема в том, что вы вызываетеthis.setTimeout()
вместоwindow.setTimeout()
.