`
zhouyrt
  • 浏览: 1128094 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

各JS引擎对Function.prototype.apply第二个参数的实现差异

阅读更多

每个function都有个apply方法,该方法有两个作用:
1,改变function的执行上下文(第一个参数非null,undefined等)
2,执行/调用该function (见:http://snandy.iteye.com/blog/420000

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

《javascript权威指南》 写道
"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(){
	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的参数呢?

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

 

 

 

分享到:
评论
1 楼 ciznx 2012-03-08  
好文章,分析得细致入理。

相关推荐

    Function.prototype.call.apply结合用法分析示例

    分析步骤如下: 1、将Function.prototype.call当成整体,call方法是由浏览器实现的本地方法,是函数类型的内部方法 var a = (Function.prototype.call).apply(function(a){return a;}, [0,4,3]); 2、fun

    Function.prototype.apply()与Function.prototype.call()小结

    apply接受两个参数,第一个制定了函数体内this对象的指向,第二个参数为一个带下标的集合(可遍历对象),apply方法把这个集合中的元素作为参数传递给被调用的函数: var func = function(a, c, c){ alert&#40;[a,...

    深入理解JS中的Function.prototype.bind()方法

    对于函数绑定(Function binding)很有可能是大家在使用JavaScript时最少关注的一点,但是当你意识到你需要一个解决方案来解决如何在另一个函数中保持this上下文的时候,你真正需要的其实就是 Function.prototype.bind...

    Function.prototype.name:符合ES6规范的Function.prototype.name垫片

    如果不可用,则调用其“ shim”方法来对Function.prototype.name进行填充。 注意: Function#name需要一个真正的ES5环境-特别是一个带有ES5吸气剂的环境。 该软件包实现了接口。 它可在ES5支持的环境中工作并符合。...

    Array.prototype.slice.apply的使用方法

    代码如下: function test(){ //将参数转为一个数组 var args = Array.prototype.slice.apply(arguments); alert&#40;args&#41;; } arguments在JavaScript语法中是函数特有的一个对象属性(Arguments对象),用来...

    理解javascript中的Function.prototype.bind的方法

    主要介绍了理解javascript中的Function.prototype.bind的方法,具有一定参考价值,有兴趣的可以了解一下。

    JS数组降维–Array.prototype.concat.apply([], arr)

    JS数组降维–Array.prototype.concat.apply二维数组降为一维数组循环降维concat降维apply和concat降维Vue2.6.11版本源码降维多维数组降为一维数组递归降维 把多维数组(尤其是二维数组)转化为一维数组是业务开发中...

    Array.prototype.at:符合ES规范的(建议的)shimpolyfillreplacement处的Array.prototype.at,可工作到ES3

    因为Array.prototype.at依赖于接收方( this值),所以Array.prototype.at要对其进行操作的数组作为第一个参数。 入门 npm install --save array.prototype.at 用法/示例 var at = require ( 'array.prototype.at' ...

    Javascript Function.prototype.bind详细分析

    当调用这个绑定函数时,绑定函数会以创建它时传入的第一个参数作为this,传入bind()方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调取原函数。  实际使用中我们经常会碰到...

    prototype.js开发笔记--让你精通prototype开发

    2.4. 对 Function 类的扩展 2.5. 对 String 类的扩展 2.6. 对 document DOM 对象的扩展 2.7. 对 Event 对象的扩展 2.8. 在 prototype.js中定义的新对象和类 2.9. PeriodicalExecuter 对象 2.10. Prototype 对象 2.11...

    Function.prototype.bind用法示例

    想必大家对Function.prototype.bind并不陌生吧,下面为大家介绍下它的简单调用及DOM调用,感兴趣的朋友可以参考下

    浅谈javascript的Array.prototype.slice.call

    发现大多人都用了Array.prototype.slice.call(argments,0),一直不明白这句是干什么的。而昨天温习了slice()方法,再参考Function.call(thisArg[, arg1[, arg2[, ...]]]),还是不得而知(我脑筋转得慢:|)。

    JavaScript中使用Object.prototype.toString判断是否为数组

    为什么要用Object.prototype.toString而不是Function.prototype.toString或者其它?这是和他们的toString解释方式有关系的。下面是ECMA中对Object.prototype.toString的解释: 代码如下: Object.prototype.toString...

    JS数组降维的实现Array.prototype.concat.apply([], arr)

    把多维数组(尤其是二维数组)转化为一维数组是业务开发中的常用逻辑,最近跟着黄轶老师学习Vue2.6.1.1版本源码时,看到源码对二维数组降维的代码,所以这里来写一篇,记录一下,加强印象 二维数组降为一维数组 循环...

    ignore-argument:像 Function.prototype.bind 部分应用忽略参数

    忽略参数像 Function.prototype.bind / 部分应用程序忽略参数。 在 NPM 和 bower 上可用,名称为ignore-argument 。 有时你需要创建临时函数只是为了忽略一些参数 function foo ( a , b ) { ... }function bar ( cb ...

    JS扩展String.prototype.format字符串拼接的功能

    2、上正文,js扩展String.prototype.format字符串拼接的功能,首先是基础功能的改造: String.prototype.format = function(){ if(arguments.length==0){ return this; } for(var s=this, i=0; i&lt;arguments.

Global site tag (gtag.js) - Google Analytics