什么是类数组对象 ArrayLike
- 拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解)
- 不具有数组所具有的方法
//类数组示例
var a = {'1':'gg','2':'love','4':'meimei',length:5};
Array.prototype.join.call(a,'+');//'+gg+love++meimei'
//非类数组示例
var c = {'1':2}; //没有length属性就不是类数组
javascript中常见的类数组有 arguments
对象和 DOM方法的返回结果。比如 document.getElementsByTagName()
。
判断一个对象是否属于类数组
function isArrayLike(o) {
if (o && // o is not null, undefined, etc.
typeof o === 'object' && // o is an object
isFinite(o.length) && // o.length is a finite number
o.length >= 0 && // o.length is non-negative
o.length===Math.floor(o.length) && // o.length is an integer
o.length < 4294967296) // o.length < 2^32
return true; // Then o is array-like
else
return false; // Otherwise it is not
}
区别 数组和类数组对象
① instanceof
② constructor
③ toString()
④ ES 提供的方法 isArray()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
<script type="text/javascript">
// 获取所有li
var lis = document.getElementsByTagName("li");
// 定义数组
var arr = [];
// 请问有几种方式来区别类数组和数组?
// typeof 用来判断类型 (是值类型还是引用类型) 返回的是一个字符串
// 第一种方式 instanceof
console.log(arr instanceof Array);
console.log(lis instanceof Array);
// 第二种方式
console.log(arr.constructor === Array)
console.log(lis.constructor === Array)
// 第三种方式
console.log(Object.prototype.toString.call(arr) === "[object Array]")
console.log(Object.prototype.toString.call(lis) === "[object Array]")
// 使用ES5提供的方法
console.log(Array.isArray(arr))
console.log(Array.isArray(lis))
</script>
</body>
</html>
类数组转换成数组之后进行操作有什么优势
由于类数组不具有数组所具有的操作数组的方法,讲类数组转换为数组之后就能调用如shift,unshift,splice,slice,concat,reverse,sort等这些强大的方法,方便快捷。
类数组转换为数组方法
Array.prototype.slice.call(arrayLike)
首先Array.prototype.slice.call(arrayLike)的结果是将arrayLike对象转换成一个Array对象。所以其后面可以直接调用数组具有的方法
Array.prototype.slice.call(arrayLike).forEach(function(element,index){ //可以随意操作每一个element了 })
(1)Array.prototype.slice表示数组的原型中的slice方法。
注意这个slice方法返回的是一个Array类型的对象。
//slice的内部实现
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}
(2)能调用call的只有方法,所以不能用[].call这种形式,得用[].slice。而call的第一个参数表示真正调用slice的环境变为了arrayLike对象。所以就好像arrayLike也具有了数组的方法。
将数组转换为参数列表(类数组)
调用apply方法的时候,第一个参数是对象(this), 第二个参数是一个数组集合, 这里就说明apply的一个巧妙用法,可以将一个数组默认的转换为一个参数列表([param1,param2,param3] 转换为 param1,param2,param3), 这个如果让我们用程序来实现将数组的每一个项,来转换为参数的列表,可能都得费一会功夫,借助apply的这点特性,所以就有了以下高效率的方法。
(1)Math.max 实现得到数组中最大的一项
因为Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组 ,但是它支持Math.max(param1,param2,param3…),所以
可以根据刚才apply的那个特点来解决 var max=Math.max.apply(null,array),这样轻易的可以得到一个数组中最大的一项 (apply会将一个数组装换为一个参数接一个参数的传递给方法)
这块在调用的时候第一个参数给了一个null,这个是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,.所以直接传递了一个null。
var arr = new Array(1,2,3,4,5); var max = Math.max.apply(null,arr); //5
(2)Array.prototype.push 可以实现两个数组合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN);
var arr1=new Array("1","2","3"); var arr2=new Array("4","5","6");
如果我们要把 arr2展开,然后一个一个追加到arr1中去,最后让arr1=[“1”,“2”,“3”,“4”,“5”,“6”]
arr1.push(arr2)显然是不行的,因为这样做会得到[“1”,“2”,“3”,[“4”,“5”,“6”]]
我们只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身)
var arrLen=arr2.length; for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]); }
所以同样也可以通过apply来转换一下这个数组,即:
var arr1=new Array("1","2","3"); var arr2=new Array("4","5","6"); Array.prototype.push.apply(arr1,arr2);
也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合.。