数组原型方法调用及函数apply调用时 类数组参数在IE8下的问题
当函数以 apply 方式调用时, 传参方式是一个由各个参数组成的数组或类数组(一个有length属性的对象),传入参数个数取决于 length 的值,例如,某个对象 args.length=3; apply 会将 args[0],args[1],args[2] 三个参数传入,如果对应的值不存在则传入了undefined.
例如:
function f(a,b,c){ console.log(a,b,c);} f.apply(null,{0:123,1:456,2:789,length:2});//123 456 undefined ,因为 length 属性值为2,值只传入了 2 个参数 f.apply(null,{10:123,11:456,12:789,length:3});// undefined undefined undefined , 因为参数对象不存在以 0、1、2 为 key 的值
但是,在IE8 及低于IE8以下的浏览器需要注意几个问题.
1、 apply 传参不接受类似 {0:'a',1:'b',length:2} 的对象,可以是 数组、arguments、 HTMLCollection 对象 和 Nodelist 对象等节点集合.
在这种情况下你也许想要把传参对象转换成数组.
2、节点集合无法调用数组的原型方法,但是 类似 {0:'a',1:'b',length:2} 的对象可以。
var nodes = document.getElementsByTagName("div"); var obj = {0:1,1:2,2:3,length:3}; var args = Array.prototype.slice.apply(nodes,[0]); //error,"Array.prototype.slice: 'this' 不是 JavaScript 对象",节点集合无法调用数组原型的方法 var args = Array.prototype.slice.apply(obj,[0]); //ok var args = Array.prototype.concat.apply([],nodes); //ok var args = Array.prototype.concat.apply([],obj); //error,"Function.prototype.apply: 缺少 Array 或 arguments 对象",普通对象无法用于 apply 传参
综合以上,可以使用 try-catch
var nodes = document.getElementsByTagName("div"); var obj = {0:1,1:2,2:3,length:3}; var params = nodes;//try nodes and obj try{ var args = Array.prototype.slice.apply(params ,[0]); }catch(err){ var args = Array.prototype.concat.apply([],params); } console.log(args);
另外,也许有这样的:
var args = Array.apply([],params);//应使用,Array.prototype.concat.apply([],params) var obj = {0:3,length:1}; var args = Array.apply([],obj); //在 obj[0] 符合数组 length 取值范围时,将得到长度为3 的空数组而不是 [3],这种情况比较容易疏忽 args.length ;//3 ( obj[0]<Math.pow(2,32)-1)
关于 concat :
数组的 concat 方法 可以被任何对象调用,得到一个数组,但是, 如果调用者不是 数组, 那么 调用者本身 仅仅作为 结果数组的第一个元素
function f(a,b){ var args = [].concat.apply(arguments,[111,222,333]); console.log(args); console.log(args.length); console.log(args[0]); } f("x","y") //执行结果 [Arguments[2], 111, 222, 333] 4 ["x", "y"]