Проверка того, является ли объект массивным
Есть ли способ проверить, является ли объект "похожим на массив", как для этих типов объектов:
- Массивы (duh)
- Типированные массивы (Uint8Array и т.д.), они вернут false, если используется
Array.isArray
- аргумент object
- нодлистов *
- Есть несколько других, которые я не могу придумать из рук
Я предполагаю, что вы можете проверить наличие свойства .length
, но объекты, не относящиеся к массиву, могут содержать свойство .length
. Я предполагаю, что все эти общие общие являются аксессуарами массива.
Ответы
Ответ 1
Насколько я нашел в своих исследованиях по этой теме, у вас есть только пара вариантов:
-
Вы можете посмотреть только на свойство .length
и принять любой объект, который, как представляется, имеет соответствующее свойство .length
, которое не является чем-то другим, что вы знаете, которого вы должны устранить (например, функция).
-
Вы можете проверить определенные объекты, похожие на массив (HTMLCollection
, nodeList
), и предубеждение в пользу них.
Вот два варианта для первого метода: тот, который не принимает нулевую длину и то, что делает (они включают предложения gilly3 и все, что мы видим в подобной функции jQuery):
// see if it looks and smells like an iterable object, but don't accept length === 0
function isArrayLike(item) {
return (
Array.isArray(item) ||
(!!item &&
typeof item === "object" &&
item.hasOwnProperty("length") &&
typeof item.length === "number" &&
item.length > 0 &&
(item.length - 1) in item
)
);
}
Это, конечно, сообщает false
для элементов с .length === 0
. Если вы хотите разрешить .length === 0
, тогда логику можно включить и в этот случай.
// see if it looks and smells like an iterable object, and do accept length === 0
function isArrayLike(item) {
return (
Array.isArray(item) ||
(!!item &&
typeof item === "object" &&
typeof (item.length) === "number" &&
(item.length === 0 ||
(item.length > 0 &&
(item.length - 1) in item)
)
)
);
}
Некоторые тестовые примеры: http://jsfiddle.net/jfriend00/3brjc/
2) После проверки, чтобы убедиться, что это не фактический массив, вы можете закодировать для проверки определенных типов объектов, подобных массиву (например, nodeList
, HTMLCollection
).
Например, здесь метод, который я использую, когда хочу, чтобы я включил объекты nodeList и HTMLCollection, похожие на массив:
// assumes Array.isArray or a polyfill is available
function canAccessAsArray(item) {
if (Array.isArray(item)) {
return true;
}
// modern browser such as IE9 / firefox / chrome etc.
var result = Object.prototype.toString.call(item);
if (result === "[object HTMLCollection]" || result === "[object NodeList]") {
return true;
}
//ie 6/7/8
if (typeof item !== "object" || !item.hasOwnProperty("length") || item.length < 0) {
return false;
}
// a false positive on an empty pseudo-array is OK because there won't be anything
// to iterate so we allow anything with .length === 0 to pass the test
if (item.length === 0) {
return true;
} else if (item[0] && item[0].nodeType) {
return true;
}
return false;
}
Ответ 2
Это дурацкий способ сделать это, но я протестировал и обнаружил, что он работает с NodeLists и массивами, но не с строками или цифрами.
myVar['somenoncollidingindex'] = true;
if(myVar.length !== undefined && myVar['somenoncollidingindex'] !== undefined) { /* hey, it array-ish! */ delete myVar['somenoncollidingindex']; }
Протестировано в движке firefox JS и в node.js(который основан на Chrome.)
Ответ 3
Ну, это зависит от того, что вы подразумеваете под массивом. Вероятно, вы могли бы перебирать цикл for следующим образом:
for (var i=0, l=obj.length; i<l; ++i) {
var item = obj[i];
}
Итак, тест прост:
function isArrayLike(obj) {
if (!obj) return false;
var l = obj.length;
if (typeof l != 'number' || l < 0) return false;
if (Math.floor(l) != l) return false;
// fast check
if (l>0 && !((l-1) in obj)) return false;
// more complete check (optional)
for (var i=0; i<l; ++i) {
if (!(i in obj)) return false;
}
return true;
}
Конечно, это не будет ловить массивы, которые малонаселены, но опять же, действительно ли они используются в качестве массивов? NodeLists и т.п. Не будут малозаселенными.
Наслаждайтесь!
Ответ 4
Я говорю, что ничто не сравнится с простотой и выразительностью расширения собственных объектов:
Object.prototype.isArrayLike = function(){ return false; };
Array.prototype.isArrayLike = function(){ return true; };
NodeList.prototype.isArrayLike = function(){ return true; };
HTMLCollection.prototype.isArrayLike = function(){ return true; };
Этот подход может вызвать конфликты между фреймворками, однако я рекомендую сохранять дистанцию от рамки, функция isArrayLike
не соответствует тому, что предлагает название.
Ответ 5
Существует способ, чтобы проверить, является ли объект массива, как или нет, даже если нет элементов в ней, с помощью этой функции здесь:
isArrayLike = function (_) {
_[0] = 0; return [].slice.call(_).length >= Object.values(_).length;
}
Это использует небольшой хак я случайно обнаружил, что позволяет определить, является ли объект (1) массив, (2) массив типа, или (3) объект/объект как.
Единственным недостатком является то, что он не работает правильно для массива-подобными, которые имеют объектно-подобные свойства добавлен, например, arguments
Ответ 6
Вы можете проверить, является ли объект итеративным:
function isIterable(o){
return (o!=null && typeof(o[Symbol.iterator])==='function');
}
Осторожно, возвращает true для строк. Если это проблема, исключите их:
function isIterable(o){
return (o!=null && typeof(o[Symbol.iterator])==='function' && typeof(o)!=='string');
}
Затем либо получите доступ к элементам, используя итератор, либо, если вы хотите использовать обычный массив [0], просто добавьте проверку длины.
Завершите функцию isArrayLike:
function isArrayLike(a){
return (
a!=null &&
typeof(a[Symbol.iterator])==='function' &&
typeof(a.length)==='number' &&
typeof(a)!=='string'
);
}
Ответ 7
Технически, (в значительной степени) каждый объект является "подобным массиву" (из-за приведения типа undefined
) в соответствии со стандартом (спецификация языка ECMAScript 2015 §7.3.17, CreateListFromArrayLike (obj [, elementTypes] )
):
7.3.17 CreateListFromArrayLike (obj [, elementTypes])
Абстрактная операция CreateListFromArrayLike используется для создания значения List, элементы которого предоставляются индексированными свойствами объекта, подобного массиву, obj. Необязательный аргумент elementTypes - это список, содержащий имена типов языка ECMAScript, которые разрешены для значений элементов создаваемого списка. Эта абстрактная операция выполняет следующие шаги:
- ReturnIfAbrupt (obj).
- Если elementTypes не был передан, пусть elementTypes будет (Undefined, Null, Boolean, String, Symbol, Number, Object).
- Если Type (obj) не является Object, генерировать исключение TypeError.
- Пусть len будет ToLength (Get (obj,
"length"
)). - ReturnIfAbrupt (len).
- Пусть список будет пустым списком.
- Пусть индекс будет 0.
- Повторите пока индекс <len
- Пусть indexName будет ToString (index).
- Пусть next будет Get (obj, indexName).
- ReturnIfAbrupt (следующий).
- Если Тип (рядом) не является элементом elementTypes, бросить исключение TypeError.
- Добавить следующий как последний элемент списка.
- Установите индекс на индекс + 1.
- Вернуться список
Сгенерировано через https://www.browserling.com/tools/html-to-markdown