简体   繁体   English

setTimeout非法调用TypeError:非法调用

[英]setTimeout Illegal invocation TypeError: Illegal invocation

Illegal invocation TypeError: Illegal invocation is thrown when calling setTimeout with a variable callback. Illegal invocation TypeError: Illegal invocation使用变量回调调用setTimeout ,引发Illegal invocation TypeError: Illegal invocation I read that this happens when this refers to another object in the callback and that bind or arrow functions are used to solve this. 我读到,当this引用回调中的另一个对象并且使用bind或arrow函数来解决此问题时,就会发生这种情况。 However, no this in my callback. 但是,在我的回调中没有this

The code is as follows: 代码如下:

 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'); 

Note that I use babel and es2015. 请注意,我使用babel和es2015。

In the sample code, functions setTimeout and clearTimeout are being invoked with an invalid context ( this ). 在示例代码中,使用无效上下文( this )调用了setTimeout和clearTimeout函数。 On possible fix is binding to the correct context ( window ): 可能的解决方法是绑定到正确的上下文( window ):

constructor(callback) {
    this._alarms = {};
    this.setTimeout = window.setTimeout.bind(window);
    this.clearTimeout = window.clearTimeout.bind(window);
    this._callback = callback || function () {};
}

It is usual to think of the this object inside a function pointing to the object to the left of the dot in the invocation: 通常会在函数中想到this对象,该函数指向调用中点左侧的对象:

alerts.create(...) // inside create(), this === alerts
   ^
   |___ "this"

When there's no dot, it depends whether the caller function is strict: 如果没有点,则取决于调用者函数是否严格:

var create = alerts.create
create() // this === Window or global
^
|_____ no dot

And

'use strict'
var create = alerts.create
create() // this === undefined
^
|_____ no dot

Given we call setTimeout without a dot, we may think that the this context doesn't matter. 给定我们调用不带点的setTimeout ,我们可能认为this上下文无关紧要。 But in browsers it will complain if you call it with a dot, or use a variant that pass as context something different than window. 但是在浏览器中,如果您使用圆点来调用它,或者使用的变体作为上下文传递的变量与窗口不同,它将发出抱怨。

Firefox: 火狐:

Uncaught TypeError: Illegal invocation 未捕获的TypeError:非法调用

Chrome: 铬:

TypeError: 'setTimeout' called on an object that does not implement interface Window. TypeError:'setTimeout'在未实现接口Window的对象上调用。


Others suggested sticking to the usual setTimeout(fn, timeout) . 其他人建议坚持通常的setTimeout(fn, timeout) Yet another way is creating an anonymous function: 还有一种方法是创建一个匿名函数:

this.setTimeout = (fn, timeout) => setTimeout(fn, timeout);

There is no this in your callback, however setTimeout is called globally. 您的回调中没有this函数,但是setTimeout被全局调用。
So this.setTimeout should be 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 

I also changed your log line because your alarm does not have a name. 我还更改了您的日志行,因为您的警报没有名称。

I got this error because I passed the wanted context to setTimeout instead of its callback 我收到此错误是因为我将wanted context传递给setTimeout而不是its callback

this the wrong code, where I pass this to setTimeout 这种错误的代码,在那里我通过thissetTimeout

setTimeout.call(this, function () {
    // this.model.starIcon = "fa-star";
    this._toggleStarIcon()
}, 150);

I correct way to pass you context is to pass it to setTimeout callback 我正确的传递上下文的方法是将其传递给setTimeout callback

I used $.proxy to do that 我用$.proxy来做到这一点

here is the correct code 这是正确的代码

setTimeout($.proxy(function () {
    // this.model.starIcon = "fa-star";
    this._toggleStarIcon()
}, this), 150);

hope this helps you 希望这对您有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM