每个function都有个apply方法,该方法有两个作用:
1,改变function的执行上下文(第一个参数非null,undefined等)
2,执行/调用该function (见:http://snandy.iteye.com/blog/420000 )
apply方法第二个参数一般认为被实现为数组,见经典的《javascript权威指南-第五版》中章节8.6.4,145页一句:
和641页关于Function.apply中提到args为一个数组。
权威指南中这个说法不太严谨,甚至自相矛盾。因为apply的第二个参数可以是arguments,而arguments并非数组。关于arguments非数组在权威指南章节8.2.2中提到。下面分别测试下:
function fun1(a){alert(a)} fun1.apply(null,[1,2,3]);//第二个参数传数组 function fun2(){ fun1.apply(null,arguments);//这里使用的是arguments,而arguments并非数组 } fun2('test');
所有浏览器中测试均没有报错,两次弹出信息框,第一次传给apply的是数组,第二次的则是arguments对象,而arguments并非数组。它是一个伪数组(Array like)。
另外,arguments并非Arguments的实例,或者说arguments的构造器不是Arguments,这点让人有点疑惑。是什么自己可以测试一下。
做一个错误的测试,传给apply的第二个参数是一个普通对象。实际上,如果第二个参数不是数组或arguments,部分浏览器相关开发工具会报错。如:
function fun(){ alert(arguments[0]); } fun.apply(null,{name:'john'});
IE8 : 缺少 Array 或 arguments 对象
Firefox3.6.3 : second argument to Function.prototype.apply must be an array
Chrome5.0.375.29 dev : Function.prototype.apply: Arguments list has wrong type
Safari4.0.3 : Result of expression '.apply' [[object Object]] is not a valid argument for 'Function.prototype.apply'.
其中,IE明确的提示要求apply的第二个参数是Array或arguments,Firefox/Chrome/Safari虽然没有明确,实际上它们都允许第二个参数可以是arguments。到这里,似乎所有浏览器都达成了默契---apply的第二个参数实现为数组,arguments。
arguments是一个伪数组(Array like),从而很自然的想到其它的伪数组(HTMLCollection,NodeList等 )如是否也可以作为apply的参数呢?
First Child
以上分别测试divs和chis,IE/Firefox/Chrome/Safari均报错,失败了。令人惊喜的是,Opera竟然通过了。即Opera中apply的第二个参数不仅允许数组,arguments,还可以传这些伪数组。
IE/Firefox/Chrome/Safari中允许传数组和arguments,那能否伪造一个伪数组欺骗apply呢?如下:
var obj = {0:'zero',1:'one',length:2}
function fun(){
alert(arguments[0]);
}
fun.apply(null,obj);
除Opera,其它浏览器还是不能通过。
继续,这次我们把对象的constructor指定为Array
var obj = {0:'zero',1:'one',length:2,constructor:Array}
function fun(){
alert(arguments[0]);
}
fun.apply(null,obj);
即使obj看起来已经很象一个数组了,但除了Opera正常运行,仍然欺骗不了IE/Firefox/Chrome/Safari,看来只有Opera与众不同。