Как преобразовать массивоподобный объект в массив
В продолжение недели оптимизации.
Я знаю 2 способа превращения массивоподобных объектов (МПО) в массив. В МПО входят: объект arguments, live collection, dead collection. Первый подход — итерация и создание нового массива из элементов МПО поштучно. Второй — применение splice в контексте МПО. При иплементации функции to_array стал вопрос: какой из способов быстрее. Чтобы не гадать, написал тесты. Тесты можно посмотреть и погонять на jsperf.
Из интересного:
- сафари6, как и опера 12.02 в 2 раза быстреe преобразует querySelectorAll() коллекцию в массив с помощью slice.
- в хроме, сафари о опере доступ к querySelectorAll коллекциям быстрее, чем к getElementsBy и document.links.
Итого: я не вижу смысла реализовывать в to_array как итерационный подход, так и splice (который в ие8 и ниже не работает). В результате, чтобы преобразовать коллекцию в массив можно использовать следующий код:
function to_array (obj) {
var i,
length,
res;
if (Object.prototype.toString.call(obj) === '[object Array]') {
return obj;
}
length = obj.length;
res = [];
for (i = 0; i < length; i += 1) {
res.push(obj[i]);
}
return res;
}
а так нельзя?
function ObjectValues(Object)
{
var Array;
for(Key in Object)
Array.push(Object[Key]);
return Array;
}
Нет. В таком случае в результат попадут значения enumerable (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty#Enumerable_attribute) свойств объекта (такие, как length, например).
Можно потрогать пример, в результирующем массиве появляется пятерка http://jsfiddle.net/Ws4Uu/
Может быть, буду не прав. Но разве не подходит более краткая запись – Array.prototype.slice.call(nodeList)
По крайней мере с псевдо-массивами когда берешь детей, определенного хтмл элемента работает.
Ты прав. Сегодня лучше не заморачиваться и использовать везде slice.
В статье я описал рассуждение почему slice не подходит (в частности из-за отсутствия поддержки в ие8, что было актуально в 2012 году, и из-за вопросов к производительности).