• 各浏览器对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中提到。下面分别测试下

    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,部分浏览器相关开发工具会报错。

    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的参数呢?

    <!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的第二个参数,那自定义一个伪数组呢?

    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

    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与众不同。

    相关:

    索引数组、关联数组和静态数组、动态数组

    将伪数组转换成数组

  • 相关阅读:
    刚加入博客园
    个人作业——软件工程实践总结作业
    前四次作业--个人总结
    项目选题报告(待就业六人组)
    结对第二次—文献摘要热词统计及进阶需求
    结对第一次—原型设计(文献摘要热词统计)
    第一次作业
    logback-spring.xml 配置说明
    k8s 微服务打包上传私库、部署、发布
    k8s离线安装监控Kubernetes集群
  • 原文地址:https://www.cnblogs.com/snandy/p/1989743.html
Copyright © 2020-2023  润新知