zoukankan      html  css  js  c++  java
  • 各浏览器对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与众不同。

    相关:

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

    将伪数组转换成数组

  • 相关阅读:
    20200209 ZooKeeper 3. Zookeeper内部原理
    20200209 ZooKeeper 2. Zookeeper本地模式安装
    20200209 Zookeeper 1. Zookeeper入门
    20200206 尚硅谷Docker【归档】
    20200206 Docker 8. 本地镜像发布到阿里云
    20200206 Docker 7. Docker常用安装
    20200206 Docker 6. DockerFile解析
    20200206 Docker 5. Docker容器数据卷
    20200206 Docker 4. Docker 镜像
    Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition
  • 原文地址:https://www.cnblogs.com/snandy/p/1989743.html
Copyright © 2011-2022 走看看