Uncaught TypeError: Illegal invocation
今天使用JavaScript的setTimeout遇到一个问题。如下是原代码:
setTimeout(raiseEle.setCustomValidity, 1000, ""); // raiseEle是一个HTMLInputElement
标题错误是在Chrome中抛出的。
先给出解决方案:
setTimeout(() => raiseEle.setCustomValidity(""), 1000)
看看原来的代码在各浏览器中的报错:
Safari | TypeError: Con only call HTMLInputElement.setCustomValidity on instances of HTMLInputElement |
Chrome | Uncaught TypeError: Illegal invocation |
Edge | Uncaught TypeError: Illegal invocation |
Firefox | Uncaught TypeError: 'setCustomValidity' called on an object that does not implement interface HTMLInputElement. |
Opera | Uncaught TypeError: Illegal invocation |
SeaMonkey | TypeError: 'setCustomValidity' called on an object that does not implement interface HTMLInputElement. |
似乎没有在raiseEle上调用该方法?
我尝试过使用以下方案:
setTimeout(raiseEle.setCustomValidity.call, 1000, raiseEle, "")
Safari | TypeError: Window is not a function |
Chrome | Uncaught TypeError: object is not a function |
Edge | Uncaught TypeError: object is not a function |
Firefox | Uncaught TypeError: Function.prototype.call called on incompatible Proxy |
Opera | Uncaught TypeError: object is not a function |
SeaMonkey | TypeError: Function.prototype.call called on incompatible Proxy |
从Safari的情况来看,难道setTimeOut底层把window当做函数调用了吗?从Chrome、Edge和Opera看,似乎确实将一个对象当做函数调用了。而Firefox的信息似乎更明确,意为在不兼容的代理上调用Function.prototype.call。但没看懂什么意思。
我也尝试过这种方案:
setTimeout(raiseEle.setCustomValidity.apply, 1000, raiseEle, [""])
在各大浏览器中均有报错:
Safari | TypeError: Window is not a function |
Chrome | Uncaught TypeError: Fonction.prototype.apply was called on #<Window>, which is a object and not a function |
Edge | Uncaught TypeError: Function.prototype.apply was called on #<Window>, which is a object and not a function |
Firefox | Uncaught TypeError: Function.prototype.call called on incompatible Proxy |
Opera | Uncaught TypeError: Fonction.prototype.apply was clled on #<window>, which is a object and not a function |
SeaMonkey | TypeError: Function.prototype.call called on incompatible Proxy |
从这次结果来看,问题似乎很明显了。在确认答案之前我们不妨给出自己的见解。我们这两次传参都是将函数对象直接传给setTimeOut,并希望在回调时像我们传入那样调用:
// 尝试1
raiseEle.setCustomValidity("");
// 尝试2
raiseEle.setCustomValidity.call(raiseEle, "");
// 尝试3
raiseEle.setCustomValidity.apply(raiseEle, [""]);
但实际上传入的是函数本身,并没有绑定(bound)调用函数的对象,此函数在setTimeout中的调用也许更像这样:
// 尝试1
Global.setCustomValidity("");
// 尝试2
Global.call(raiseEle, "");
// 尝试3
Global.apply(raiseEle, [""]);
这里的Global是运行时从最开始就创建的对象,在浏览器中通常为window。我们在node.js中测试一下:
let test = {callback(){console.log("callback")}
}setTimeout(test.callback, 100)
但结果和我预想的不同,各浏览器包括node.js都能顺利找到test.callback的调用者。
难道是因为函数在prototype上的缘故吗?
function Test(){this.id = Math.random()
}Test.prototype.callback = function(){console.log("callback", this.id);
}setTimeout((new Test()).callback, 1000)
setTimeout(() => (new Test()).callback(), 2000)
这次不仅将函数定义在了对象的prototype上,还在构造函数中为实例添加了id属性。结果1秒后调用log出的id属性为undefined,而2秒后log出的id属性没问题。
以上两个示例说明定义在对象中的函数,其this已经死死绑定到改对象,而在prototype中定义的函数没有绑定this到实例,在setTimeout调用时也不会将调用者当做this传入,而是仅仅将函数体本身调用一次。
为了验证结论,我翻开了红宝书:
对象中方法的this会被解析为该对象。
这个this和调用上下文无关,无论该函数如何被调用,或者用一个指针指向该函数再调用指针,该方法也会使用正确的this。
以下代码证实结论:
let mmp = (new Test()).callback;
mmp();
let nnp = () => (new Test()).callback()
nnp();
mmp函数输出this.id值为undefined,而nnp函数输出this.id值为一个浮点数。
这样很容易解释为什么第二种和第三种方案也会报错了。因为window对象中没有call和apply函数,或者window对象不是一个Function,不能调用call和apply来调用,因此才会出现诸如window对象不是函数以及Function.prototype.call和Function.prototype.apply调用使用不正确的代理这些错误。
结论:
在setTimeout中调用函数对象不会理会函数的调用上下文,而直接单独地调用函数体本身。
Uncaught TypeError: Illegal invocation相关推荐
- Ajax方式上传文件报错Uncaught TypeError: Illegal invocation
今天使用ajax上传文件时,出现了错误.数据传输的方式是通过定义formData完成的,提交的文件对象也设置为dom对象,但是还是不能发送请求.F12看到后台报了个错误:Uncaught TypeEr ...
- 【JavaScript】Uncaught TypeError: Illegal invocation
通过JQuery的ajax调用post方法提交时,报了这个错误Uncaught TypeError: Illegal invocation,这是因为在提交的变量时有非法值,比如{title:$titl ...
- Uncaught TypeError: Illegal invocation问题解决方法
Uncaught TypeError: Illegal invocation问题解决方法 参考文章: (1)Uncaught TypeError: Illegal invocation问题解决方法 ( ...
- 奇怪的报错(uncaught typeerror illegal invocation)
奇怪的错误 uncaught typeerror illegal invocation 这个错误一般是ajax引起的,分为两种情况 1请求类型有误,即get请求,但后台实际为post请求 2即ajax ...
- Uncaught TypeError:Illegal invocation
Uncaught TypeError:Illegal invocation: 中文意思是:未捕获的异常:非法调用 我是在使用ajax发送请求时出现的这个错误, 参考:https://www.cnblo ...
- Uncaught (in promise) TypeError: Illegal invocation
调接口时加上: contentType:false, processData:false
- jquery ajax报Uncaught TypeError :Illegal invocation
使用jquery ajax异步提交的时候报Uncaught TypeError :Illegal invocation错误,报错信息如图: 网上关于这个问题有两个解决方案: 1.请求类型有误,如,po ...
- ajax上传文件 获取失败,Ajax上传文件/照片时报错TypeError :Illegal invocation的解决方法...
本篇文章给大家带来的内容是关于Ajax上传文件/照片时报错TypeError :Illegal invocation的解决方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 问题 A ...
- “Uncaught TypeError: string is not a function”
http://www.cnblogs.com/haitao-fan/archive/2013/11/08/3414678.html 今天在js中写了一个方法叫做search(),然后点击按钮的时候提示 ...
- chrome浏览器不能录音:Uncaught TypeError: Cannot read property ‘getUserMedia‘ of undefined解决方法
Uncaught TypeError: Cannot read property 'getUserMedia' of undefined解决方法 javascript 打不开浏览器录音功能的问题解决方 ...
最新文章
- 命令别名的设置alias,unalias
- 从实现iPhone的OAuth封装看国内互联网和开放平台
- 关于Input内容改变的触发事件
- 屏蔽敏感词的正则表达式
- CGI方式获取RTX中用户的电话和邮箱
- php实现微信清粉功能,PHP实现微信提现功能
- Android之jni编译报错comparsion between signed and unsigned integer expressions解决办法
- 使用Tomcat部署应用
- java xml接口实例化_Spring简介及xml配置
- 编程体系结构(07):JavaEE之Web开发
- 苹果电风扇软件Macs Fan Control Pro安装教程
- WIN7使用各种激活软件都不管用的解决办法
- 竖着的seekbar_自定义竖着的SeekBar | 学步园
- excel 如何冻结多行多列
- 深入浅出Meta Learning - 让机器学会如何去学习
- 模拟信号拉线位移编码器是如何来校准的?
- JUnit version 3.8 or later expected
- 日常收入和支出怎么记账
- 解决控制台Could not resolve view with name ...
- HTTP下载文件校验失败原因分析与解决