​​javascript 类数组​​

javascript

更新于 2019-03-01   约 8 分钟

在线的《javascript权威指南》有对该概念的解释。

那么,什么是javascript 类数组呢?

定义:

  • 拥有​​length​​​属性,​​length-0​​​可隐式转换为number类型,并且不大于​​Math.pow(2,32)​​​(比如:​​22.33​​​和​​'022'​​都满足条件)
  • 不具有数组所具有的方法

类数组示例:

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()​​。

类数组判断

javascript权威指南》上给出了代码用来判断一个对象是否属于“类数组”。如下:

// Determine if o is an array-like object.
// Strings and functions have numeric length properties, but are
// excluded by the typeof test. In client-side JavaScript, DOM text
// nodes have a numeric length property, and may need to be excluded
// with an additional o.nodeType != 3 test.
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 arrLike1 = { length: 1.2 };
var arrLike2 = { length: -10 };
var arrLike3 = { length: '10' };

当然,除却人为“造作”因素,正常的​​length​​应当是正整数。

我们可以对照一下:MDN Array.from 的polyfill​ , 这个方法中对​​length​​的判断可以看一下。

var toInteger = function (value) {
var number = Number(value);
if (isNaN(number)) { return 0; }
if (number === 0 || !isFinite(number)) { return number; }
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1; //此处length应当为Math.pow(2, 32) - 1
var toLength = function (value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};

类数组表现

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

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']: true array copy
Array.prototype.map.call(a, function(x) {
return x.toUpperCase();
}); // => ['A','B','C']:

类数组对象转化为数组

有时候处理类数组对象的最好方法是将其转化为数组。

有两种实现方法:

1.数组​​slice​​方法借用

Array.prototype.slice.call(arrLike)

2.Array.from

Array.from(arrLike)

然后就可以直接使用数组方法啦。

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

ps​: 两个处理方法存在细节差异,比如处理​​{length: 1}​​​这个对象时,结果就不一样,​​Array.from​​​处理结果是长度为1并且填充值为​​undefined​​​,而​​Array.prototype.slice​​​处理结果则相同于​​new Array(1)​​。

对于IE9以前的版本(DOM实现基于COM),我们可以使用​​makeArray​​来实现。

// 伪数组转化成数组
var makeArray = function(obj) {
if (!obj || obj.length === 0) {
return [];
}
// 非伪类对象,直接返回最好
if (!obj.length) {
return obj;
}
// 针对IE8以前 DOM的COM实现
try {
return [].slice.call(obj);
} catch (e) {
var i = 0,
j = obj.length,
res = [];
for (; i < j; i++) {
res.push(obj[i]);
}
return res;
}

};

参考:

1.https://www.inkling.com/read/...

2.JavaScript 的怪癖 8:“类数组对象