【JavaScript 漫游】【006】数据类型 array

【JavaScript 漫游】【006】数据类型 array_第1张图片
文章简介

本文为【JavaScript 漫游】专栏的第 006 篇文章,记录笔者在了解 JS 数据类型 array 中摘录的知识点。

  1. 数组的本质是对象
  2. 属组的 length 属性
  3. for ... in 循环和数组的遍历
  4. 数组的空位
  5. 类数组对象

除了上述 5 个重要知识点,学习数组更为重要的是掌握它的静态方法和实例方法,笔者计划再后面单独写一篇文章进行总结。

数组本质上是一种特殊的对象

typeof 运算符返回数据的数据类型是 object,这说明在本质上,数组属于一种特殊的对象。而它的特殊性体现在,它的键名是按次序排列的一组整数。

var arr = ['a', 'b', 'c'];
Object.keys(arr);  // ['0', '1', '2']

length 属性

数组的 length 属性,返回数组的成员数量。

['a', 'b', 'c'].length;  // 3

只要是数组,就一定有 length 属性。该属性是一个动态的值,等于键名中的最大整数加上 1。要注意的是,数组的数字键不需要连续,length 属性的值总是比最大的那个整数键大 1

var arr = ['a', 'b'];
arr.length // 2

arr[2] = 'c';
arr.length // 3

arr[9] = 'd';
arr.length // 10

arr[1000] = 'e';
arr.length // 1001

length 属性是可写的,如果人为设置一个小于当前成员个数的值,该数组的成员数量会自动减少到 length 设置的值。如果将 length 属性设为 0,就可以清空数组。如果设的值不合法,比如 -1,JS 会报错。

var arr = [ 'a', 'b', 'c' ];
arr.length // 3

arr.length = 2;
arr // ["a", "b"]

arr.length = 0;
arr // []

for...in 循环和数组的遍历

既然数组是一种特殊的对象,那么 in 运算符和for...in循环同样能作用到数组上。

in 运算符检查某个键名是否存在。

var arr = [];
arr[100] = 'hello';
1 in arr;  // false
100 in arr;  // true

for...in循环可以遍历数组的所有键名。特别注意的是,它不仅会遍历数组的数组键,也会遍历非数组键。终究是因为数组本质是一种对象,它的标准键名是数值,但如果人为赋予字符串键名是没有问题的。

var arr = ['a', 'b', 'c'];
arr['hello'] = 'world';
arr.length; // 3
for (var key in arr) {
  console.log(key);
}
// 0
// 1
// 2
// hello

基于 for...in 循环会遍历到非数组键,所以,遍历数组的时候最好不要用for...in,转而使用for循环或while循环更好。

笔者认为,遍历对象使用 Object.keys 方法,遍历数组使用for循环以及数组的实例方法forEach是最好的,工作遍历数组时使用forEach方法比for循环的频率更高。

数组的空位

当数组的某个位置是空元素,就称该数组存在空位。

var arr = [1, , 1];
a.length;  // 3
a[1];  // undefined

数组的某个位置是空位,与某个位置是 undefined,是不一样的。如果是空位,使用数组的 forEach 方法、for...in 结构、以及Object.keys 方法进行遍历,空位都会被跳过。而由于空位的存在对 length 属性没有影响,使用 length 属性配合 for 循环遍历数组的时候,要确保数组没有空位。

var arr = [1, , 1];
arr.forEach(function(value, index) {
  console.log('arr[' + index + '] = ' + value);
})
// arr[0] = 1
// arr[2] = 1

for (var key in arr) {
  console.log('arr[' + key + '] = ' + arr[key]);
}
// arr[0] = 1
// arr[2] = 1

Object.keys(arr); // ['0', '2']

for (var i = 0; i < arr.length; i++) {
  console.log('arr[' + i + '] = ' + arr[i]);
}
// arr[0] = 1
// arr[1] = undefined,值为 undefined 在实际开发过程会诱发报错
// arr[2] = 1
var arr = [1, undefined, 1];
arr.forEach(function(value, index) {
  console.log('arr[' + index + '] = ' + value);
})
// arr[0] = 1
// arr[1] = undefined
// arr[2] = 1

for (var key in arr) {
  console.log('arr[' + key + '] = ' + arr[key]);
}
// arr[0] = 1
// arr[1] = undefined
// arr[2] = 1

Object.keys(arr); // ['0', '1', '2']

for (var i = 0; i < arr.length; i++) {
  console.log('arr[' + i + '] = ' + arr[i]);
}
// arr[0] = 1
// arr[1] = undefined
// arr[2] = 1

由此可知,遍历数组的最好方法就是 forEach

简单总结,空位就是数组没有这个元素,所以不会被遍历到,而 undefined 表示数组有这个元素,值是 undefined ,所以遍历不会跳过。

类数组对象

如果一个对象的所有键名都是正整数或零,并且有 length 属性,那么这个对象就很像数组,语法上称为 类数组对象

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function

类数组对象并不是数组,因为它们不具备数组特有的方法,它们的根本特征是有 length 属性,只要有 length 属性,就可以认为这个对象类似于数组。但是有一个问题,这种 length 属性不是动态值,不会随着成员的变化而变化。

var obj = {
  length: 0
};
obj[3] = 'd';
obj.length // 0

典型的类数组对象是函数的 arguments 对象,以及大多数 DOM 运算集,还有字符串。

数组的 slice 方法可以将类数组对象变成真正的数组。

var str = 'hello';
var arr = Array.prototype.slice.call(str);

除了转为真正的数组,类数组对象还有一个办法可以使用数组的方法,就是通过 call 方法将数组的方法放到对象上。

function print(value, index) {
  console.log(index + ' : ' + value);
}
var str = 'hello';
Array.prototype.forEach.call(str, print);

要注意的是,使用 call 方法调用 forEach 这种方式,比直接使用数组原生的 forEach 方法要慢,所以最好先将类数组对象转为真正的数组,然后再直接调用数组的 forEach 方法。

你可能感兴趣的:(JavaScript,漫游,javascript,前端)