setTimeout 非法调用类型错误:非法调用
Posted
技术标签:
【中文标题】setTimeout 非法调用类型错误:非法调用【英文标题】:setTimeout Illegal invocation TypeError: Illegal invocation 【发布时间】:2017-12-02 14:00:27 【问题描述】: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。
【问题讨论】:
该函数抛出错误,因为您已将对它的引用复制到您自己的对象,然后您使用自己的对象作为this
上下文调用它。回调不引用this
没有区别。问题是您调用的是this.setTimeout()
而不是window.setTimeout()
。
【参考方案1】:
在示例代码中,函数 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
对象指向调用中点左侧的对象:
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
上下文无关紧要。但在浏览器中,如果你用点调用它,或者使用作为上下文传递的变体不同于窗口,它会报错。
火狐:
未捕获的类型错误:非法调用
铬:
TypeError:在未实现接口 Window 的对象上调用了“setTimeout”。
其他人建议坚持通常的setTimeout(fn, timeout)
。
还有一种方法是创建一个匿名函数:
this.setTimeout = (fn, timeout) => setTimeout(fn, timeout);
【讨论】:
或者使用 setTimeout 和 clearTimeout,没有这个反模式代码【参考方案2】:您的回调中没有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
我还更改了您的日志行,因为您的警报没有名称。
【讨论】:
【参考方案3】:我收到此错误是因为我将wanted context
传递给setTimeout
而不是its callback
这是错误的代码,我将this
传递给setTimeout
setTimeout.call(this, function ()
// this.model.starIcon = "fa-star";
this._toggleStarIcon()
, 150);
我传递上下文的正确方法是将其传递给setTimeout callback
我使用$.proxy
来做到这一点
这是正确的代码
setTimeout($.proxy(function ()
// this.model.starIcon = "fa-star";
this._toggleStarIcon()
, this), 150);
希望对你有帮助
【讨论】:
以上是关于setTimeout 非法调用类型错误:非法调用的主要内容,如果未能解决你的问题,请参考以下文章
Jquery 和 HTML FormData 返回“未捕获的类型错误:非法调用”