简单来讲,和数组相似,拥有
length
属性,能够经过索引来访问或设置里面的元素,可是不能使用数组的方法。javascript
看个例子:html
arr[0];
// => "dazhi"
复制代码
这里的arr
必定是一个数组吗?不必定,也多是一个对象。前端
let arr = {
0: 'dazhi'
}
console.log(arr[0]); // dazhi
复制代码
再来看个例子:java
let arr = ['name', 'age', 'job'];
// 建立一个类数组对象
let arrLike = {
0: 'name',
1: 'age',
2: 'job',
length: 3
}
复制代码
注意:这边arrLike必须加上length
属性,否则它就是一个普通对象而已。git
为何叫作类数组对象呢?咱们从读写、获取长度、遍历这三个方面来看看这两个对象。github
console.log(arr[0]); // name
console.log(arrLike[0]); // name
arr[0] = 'new name';
arrLike[0] = 'new name';
console.log(arr[0]); // new name
console.log(arrLike[0]); // new name
复制代码
console.log(arr.length); // 3
console.log(arrLike.length); // 3
复制代码
for (let i = 0;i < arr.length; i++){
console.log(arr[i]);
}
// name
// age
// job
for (let i = 0;i < arrLike.length; i++){
console.log(arrLike[i]);
}
// name
// age
// job
复制代码
有没有很像?当咱们使用使用数组的方法呢?继续往下看:数组
arr.push('gender');
arrLike.push('gender'); // 报错
复制代码
原形毕露了,终归是类数组。app
那若是类数组
就想用数组的方法呢?能够把类数组
转换为数组。函数
var arrLike2 = Array.prototype.slice.call(arrLike);
arrLike2.push('gender');
console.log(arrLike2[3]); // gender
复制代码
var arrLike3 = Array.from(arrLike);
arrLike3.push('gender');
console.log(arrLike3[3]); // gender
复制代码
var arrLike4 = Array.prototype.splice.call(arrLike, 0);
arrLike4.push('gender');
console.log(arrLike4[3]); // gender
复制代码
若是length
值和实际元素不相等呢?学习
let arrLike = {
0: 'name',
1: 'age',
length: 3
}
console.log(Array.from(arrLike)); // ["name", "age", undefined]
复制代码
能够看到,若是length
值大于实际元素的数量,不足的将用undefined
填充。
若是反过来呢?
let arrLike = {
0: 'name',
1: 'age',
length: 1
}
console.log(Array.from(arrLike)); // ["name"]
复制代码
最终只保留了一个元素。可见,length
值是决定最终生成数组的长度的,多余的去掉,不足的用undefined
填充。
那若是咱们索引不从0和1开始,能够吗?
let arrLike = {
2: 'name',
3: 'age',
length: 2
}
console.log(Array.from(arrLike)); // [undefined, undefined]
复制代码
可见,0和1是有用的,会影响到最终的填充索引。
说了这么多,类数组能用来作什么?
还记得arguments
对象吗?它就是一个类数组对象。咱们看下MDN
上对其的描述:
arguments
对象是全部(非箭头)函数中均可用的局部变量。你可使用arguments
对象在函数中引用函数的参数。arguments
对象不是一个Array
。它相似于Array
,但除了length属性和索引元素以外没有任何Array
属性。例如,它没有pop
方法。但它能够被转换为一个真正的Array
。
MDN地址:developer.mozilla.org/zh-CN/docs/…
看个例子:
function foo(a, b, c) {
console.log(arguments);
}
foo(1, 2, 3);
复制代码
控制台看下打印结果:
咱们能够经过arguments
对象在函数内部引用传递进来的参数:
function foo(a, b, c) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
foo(1, 2, 3);
// 1
// 2
// 3
复制代码
arguments
的length
属性表明的是实参的个数,由于咱们调用函数的时候,有时候并非全部参数都须要传入,看下面的代码:
function foo(a, b, c) {
console.log('实参的个数:' + arguments.length); // 1
}
foo(1);
console.log('形参的个数为:' + foo.length); // 3
复制代码
function foo(a, b, c, d) {
// "use strict";
console.log(a, arguments[0]); // 1 1
// 改变形参
a = 11;
console.log(a, arguments[0]); // 11 11
// 改变arguments
arguments[1] = 22;
console.log(b, arguments[1]); // 22 22
// 未传入的参数
console.log(c); // undefined
c = 3;
console.log(c, arguments[2]); // 3 undefined
arguments[3] = 4;
console.log(d, arguments[3]); // undefined 4
}
foo(1, 2);
复制代码
总结:
arguments
的值会共享,没有传入的参数,不会共享arguments
的值都不会共享将参数从一个函数传递到另外一个函数。
function foo() {
bar.apply(this, arguments);
}
function bar(a, b, c) {
console.log(a, b, c);
}
foo(1, 2, 3);
// 1 2 3
复制代码
arguments
除了能够用上面的几个转为数组的方法,还可使用...
展开运算符。
function bar(a, b) {
// 用...把argumens转为数组
console.log([...arguments]); // [1, 2]
}
bar(1, 2);
复制代码
可是若是应用到普通的类数组对象呢?
let arrLike5 = {
a: 1,
b: 2,
length: 2
}
console.log([...arrLike5]); // 报错 Uncaught TypeError: arrLike5 is not iterable
复制代码
报错的意思是:arrLike5不是可迭代的,也就证明了arguments
除了是类数组对象,仍是一个可迭代对象,而咱们自定义的对象并不具有可迭代功能,因此不能使用展开运算符。
由于咱们自定义的类数组对象不具有可迭代功能,因此也没办法使用for...of
来遍历:
let arrLike = {
0: 'name',
1: 'age',
2: 'job',
length: 3
}
for (let arrItem of arrLike) {
console.log(arrItem);
}
// 一样会报错 Uncaught TypeError: arrLike is not iterable
复制代码
那么forEach
和for...in
呢?
forEach
是数组的方法,天然也没办法使用。
来看下for...in
:
let arrLike = {
0: 'name',
1: 'age',
2: 'job',
length: 3
}
for (let index in arrLike) {
console.log(index);
}
// 0
// 1
// 2
// length
复制代码
for...in
是遍历对象的可枚举属性,会把length
也遍历出来。
因此只有for循环能够正确遍历类数组对象。
另外,arguments
的应用其实还有不少,这里就不继续展开了,你们有兴趣能够本身再去找资料学习一下,好比:
咱们在页面上随便写几个p
标签:
<p></p>
<p></p>
<p></p>
复制代码
而后用document.getElementsByTagName()
获取:
var ps = document.getElementsByTagName('p');
console.log(ps);
复制代码
能够看到,里面也有length
属性,可是它并非一个数组,咱们能够来检测一下:
// 类数组对象不能使用数组的方法
ps.push('a'); // 报错:Uncaught TypeError: ps.push is not a function
console.log(Object.prototype.toString.call(ps)); // [object HTMLCollection]
console.log(Object.prototype.toString.call([])); // [object Array]
复制代码
好了,本文就先到这里了。
感谢您的阅读,但愿对你有所帮助。因为本人水平有限,若是文中有描述不当的地方,烦请指正,很是感谢。
欢迎你们关注个人公众号前端帮帮忙
,一块儿交流学习,共同进步!
参考: