各浏览器对apply第二个参数的实现差异
每个函数都有个apply方法,该方法有两个作用:
- 改变函数的执行上下文(第一个参数非null,undefined)
- 执行/调用该函数
apply方法第二个参数一般认为被实现为数组,见经典的《javascript权威指南-第五版》中章节8.6.4,145页:
"apply()方法和call()方法相似,只不过要传递给函数的参数是由数组指定的:"
和641页关于Function.apply中提到args为一个数组。
权威指南中这个说法不太严谨,甚至自相矛盾。因为apply的第二个参数可以是arguments,而arguments并非数组。关于arguments非数组在权威指南章节8.2.2中提到。下面分别测试下
1 2 3 4 5 6 7 8 | function fun1(a){alert(a)} fun1.apply( null ,[1,2,3]); //第二个参数传数组 function fun2(){ //这里使用的是arguments,而arguments并非数组 fun1.apply( null ,arguments); } fun2( 'test' ); |
所有浏览器中测试均没有报错,两次弹出信息框,fun1所传的是数组,fun2是arguments对象,而arguments并非数组。它是一个伪数组(Array like)。
另外,arguments并非Arguments的实例,或者说arguments的构造器不是Arguments,这点让人有点疑惑。是什么自己可以测试一下。
下面做一个错误的测试,传给apply的第二个参数是一个普通对象。实际上,如果第二个参数不是数组或arguments,部分浏览器相关开发工具会报错。
1 2 3 4 | function fun(){ alert(arguments[0]); } fun.apply( null ,{name: 'john' }); |
各浏览器表现
- IE6/7/8 : 缺少 Array 或 arguments 对象
- IE9 : undefined
- Firefox : second argument to Function.prototype.apply must be an array
- Chrome : Function.prototype.apply: Arguments list has wrong type
- Safari : Result of expression '.apply' [[object Object]] is not a valid argument for 'Function.prototype.apply'
其中,IE6/7/8明确的提示要求apply的第二个参数是Array或arguments,Firefox控制台提示第二个参数须是array,Chrome/Safari控制台则提示所传参数是错误的类型,没说必须是数组或arguments对象之类的。
纵观这些提示,IE6/7/8的最人性化了,它明确告知了所传参数的类型。实际上所有浏览器都允许第二个参数可以是arguments。到这里,似乎所有浏览器都达成了默契---apply的第二个参数实现为数组,arguments。
既然第二个参数能传arguments,arguments是一个伪数组(Array like),从而很自然的想到其它的伪数组(HTMLCollection,NodeList等 )如是否也可以作为apply的参数呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!DOCTYPE HTML> <HTML> <HEAD> <script> window.onload = function (){ var divs = document.getElementsByTagName( 'div' ); var chis = document.body.children; function fun(){ alert(arguments[0]); } fun.apply( null ,divs); //fun.apply(null,chis); } </script> </HEAD> <BODY> <p>First Child</p> <div id= "d1" ><div> <div id= "d2" ><div> </BODY> </HTML> |
以上分别测试divs和chis,IE6/7/8/Firefox/Chrome/Safari均报错,失败了。令人惊喜的是,IE9/Opera竟然通过了。即IE9/Opera中apply的第二个参数不仅允许数组,arguments,还可以传这些伪数组。
既然HTMLCollection,NodeList在IE9/Opera下能作为apply的第二个参数,那自定义一个伪数组呢?
1 2 3 4 5 | var obj = {0: 'zero' ,1: 'one' ,length:2} function fun(){ alert(arguments[0]); } fun.apply( null ,obj); |
我们知道JQuery对象就是一个伪数组(Array Like),上面的obj也是这样的,具有索引和length。除IE9/Opera弹出了“zero”,其它浏览器提示出错。
也许我们的这个Array Like不够好,继续,这次我们把对象的constructor指定为Array
1 2 3 4 5 | var obj = {0: 'zero' ,1: 'one' ,length:2,constructor:Array} function fun(){ alert(arguments[0]); } fun.apply( null ,obj); |
即使obj看起来已经很象一个数组了,但除了Opera正常运行,仍然欺骗不了IE6/7/8/Firefox/Chrome/Safari,看来只有IE9/Opera与众不同。
相关:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端