setTimeout Недопустимый вызов TypeError: Недопустимый вызов

1

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.

  • 2
    Функция выдает ошибку, потому что вы скопировали ссылку на нее в свой собственный объект, а затем вызываете ее со своим собственным объектом в качестве контекста this . Не имеет значения, что обратный вызов не относится к this . Проблема в том, что вы вызываете this.setTimeout() вместо window.setTimeout() .
Теги:
ecmascript-6

2 ответа

2
Лучший ответ

В примере кода функции 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);
  • 0
    или используйте setTimeout и clearTimeout без этого антипаттернного кода
1

В вашем 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

Я также изменил вашу строку журнала, потому что у вашего сигнала тревоги нет имени.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню