数组和类数组

数组

在js中,数组可以容纳任何类型的值,可以是字符串、数字、对象,甚至是其他数组(多维数组就是通过这种方式来实现的):

var a = [1, '2', [3]];
a.length; // 3

对数组声明后即可向其中加入值,不需要预先设定大小:

var a = [];
a.length; // 0

a[0] = 1;
a[1] = '2';
a[2] = [3];
a.length; // 3

使用delete运算符可以将单元从数组中删除,但是删除后,数组的length属性并不会发生变化。

创建稀疏数组,空白单元为undefined,但仍占有length;字符串键值不占有length;字符串键值能够被强制转换为十进制数字的话,会被当作数字索引来处理:

var a = [];
a[0] = 1;
a['2'] = 2; // 稀疏数组,仍存在a[1];该字符串键值可以转换为数字,当作a[2]处理
a['foo'] = 3; // 该字符串键值不能转为数字,不占有length

a.length; // 3
a[0] === 1 
a[1] === undefined 
a[2] === 2

类数组

有时需要将类数组(一组通过数字索引的值)转换为真正的数组,这一般通过数组工具函数(如indexof(..)、concat(..)、forEach(..)等)实现。

一些DOM查询操作会返回DOM元素列表,它们并非真正意义上的数组,但十分类似;通过arguments对象(类数组)将函数的参数当作列表来访问(从ES6开始已废止)。工具函数slice(..)经常被用于这类转换:

function foo() {
    var arr = Array.prototype.slice.call(arguments);
    arr.push('bam');
    console.log(arr);
}
foo('bar', 'baz'); // ['bar', 'baz', 'bam']

ES6中的内置工具函数Array.from(..)也能实现同样的功能:

var arr = Array.from(arguments);

类数组详解

定义

拥有length属性,其他属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解);不具有数组所具有的方法。实际上,只要有length属性,且它的属性值为number类型就行。

类数组示例:

var a = {'1':'gg','2':'love','4':'meimei',length:5};
Array.prototype.join.call(a,'+'); // '+gg+love+meimei'

非类数组示例(没有length属性,所以不是类数组):

var c = {'1':2};

js中常见的类数组有arguments对象和DOM方法的返回结果。

类数组判断

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
}

类数组表现

之所以称为‘类数组’,就是因为和‘数组’类似。不能直接使用数组方法,但你可以像使用数组那样,使用类数组。

var a = {'0':'a', '1':'b', '2':'c', length:3};  // An array-like object
Array.prototype.join.call(a, '+'');  // => 'a+b+c'
Array.prototype.slice.call(a, 0);   // => ['a','b','c']
Array.prototype.map.call(a, function(x) { 
    return x.toUpperCase();
});                                 // => ['A','B','C']

类数组对象转化为数组

有时候处理类数组对象的最好方法是将其转化为数组,然后就可以直接使用数组方法啦。

Array.prototype.slice.call(arguments)

var a = {'0':1,'1':2,'2':3,length:3};
var arr = Array.prototype.slice.call(a); // arr === [1,2,3]