各浏览器对apply第二个参数的实现差异

每个函数都有个apply方法,该方法有两个作用:
1,改变函数的执行上下文(第一个参数非null,undefined)。
2,执行/调用该函数。

apply方法第二个参数一般认为被实现为数组,见经典的《javascript权威指南-第五版》中章节8.6.4,145页:

"apply()方法和call()方法相似,只不过要传递给函数的参数是由数组指定的:"

和641页关于Function.apply中提到args为一个数组。

 

权威指南中这个说法不太严谨,甚至自相矛盾。因为apply的第二个参数可以是arguments,而arguments并非数组。关于arguments非数组在权威指南章节8.2.2中提到。下面分别测试下


1 function fun1(a){alert(a)}
2 fun1.apply( null ,[1,2,3]); //第二个参数传数组
3  
4 function fun2(){
5      //这里使用的是arguments,而arguments并非数组
6      fun1.apply( null ,arguments);
7 }
8 fun2( 'test' );

所有浏览器中测试均没有报错,两次弹出信息框,fun1所传的是数组,fun2是arguments对象,而arguments并非数组。它是一个伪数组(Array like)。
另外,arguments并非Arguments的实例,或者说arguments的构造器不是Arguments,这点让人有点疑惑。是什么自己可以测试一下。

下面做一个错误的测试,传给apply的第二个参数是一个普通对象。实际上,如果第二个参数不是数组或arguments,部分浏览器相关开发工具会报错。


1 function fun(){
2      alert(arguments[0]);
3 }
4 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的参数呢?


01 <!DOCTYPE HTML>
02 < HTML >
03   < HEAD >
04    < script >
05      window.onload = function(){    
06          var divs = document.getElementsByTagName('div');
07          var chis = document.body.children;
08          function fun(){
09              alert(arguments[0]);
10          }
11          fun.apply(null,divs);
12          //fun.apply(null,chis);
13      }
14    </ script >
15   </ HEAD >
16   < BODY >
17      < p >First Child</ p >
18      < div id = "d1" >< div >
19      < div id = "d2" >< div >
20   </ BODY >
21 </ HTML >

以上分别测试divs和chis,IE6/7/8/Firefox/Chrome/Safari均报错,失败了。令人惊喜的是,IE9/Opera竟然通过了。即IE9/Opera中apply的第二个参数不仅允许数组,arguments,还可以传这些伪数组。

 

既然HTMLCollection,NodeList在IE9/Opera下能作为apply的第二个参数,那自定义一个伪数组呢?


1 var obj = {0: 'zero' ,1: 'one' ,length:2}
2 function fun(){
3      alert(arguments[0]);
4 }
5 fun.apply( null ,obj);

我们知道JQuery对象就是一个伪数组(Array Like),上面的obj也是这样的,具有索引和length。除IE9/Opera弹出了“zero”,其它浏览器提示出错。

也许我们的这个Array Like不够好,继续,这次我们把对象的constructor指定为Array


1 var obj = {0: 'zero' ,1: 'one' ,length:2,constructor:Array}
2 function fun(){
3      alert(arguments[0]);
4 }
5 fun.apply( null ,obj);

即使obj看起来已经很象一个数组了,但除了Opera正常运行,仍然欺骗不了IE6/7/8/Firefox/Chrome/Safari,看来只有IE9/Opera与众不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值