Массивоподобные объекты и работа с ними
Массивоподобным объектом является любой объект, содержащий числовые индексы и свойство length
. Например объект arguments
является массивоподобным объектом. Объект описанный следующим образом:
var arrayLikeObject = {
0: 'one',
1: 'two',
length: 2
};
является массивоподобным. Коллекции элементов, возвращенных из методов document.querySelectorAll
, document.getElementsByTagName
а так же объеты, возвращаемые библиотекой jQuery
являются массивоподобными объектами. Этот список того, где можно встретить массивоподобные объекты, не полон. Все примеры ниже применимы к любым массивоподобным объектам.
В консоли браузера массивоподобные объекты могут отображаться так же как и массивы. При этом массивоподобные объекты не являются массивами: у массивоподобных объектов нет методов, которые присущи массивам (indexOf
, filter
, forEach
и другие). Поэтому при попытке вызвать метод массива у массивоподобного объекта такой код завершится исключением:
function hasTwo() {
return arguments.indexOf('two') !== -1;
}
hasTwo('one', 'two', 'three'); // Error
Как работать с массивоподобными объектами
Цикл for
Цикл for
корректно работает с массивоподобными объектами. Например функция, определяющая есть ли среди переданных ей аргументов значение 'two' может выглядеть следующим образом:
function hasTwo() {
for (var i = 0; i < arguments.length; i += 1) {
if (arguments[i] === 'two') {
return true;
}
}
return false;
}
console.log(hasTwo('uno', 'tuo', 'tre')); // false
console.log(hasTwo('one', 'two', 'three')); // true
Вызов методов массивов в контексте массивоподобного объекта (одалживание метода)
Вызов методов массивов с помощью call
и apply
, и передачей контектом вызова ссылки на массивоподобный объект.
Например функция, определяющая есть ли среди переданных ей аргументов значение 'two' будет выглядеть следующим образом:
function hasTwo() {
return Array.prototype.indexOf.call(arguments, 'two') !== -1
}
console.log(hasTwo('uno', 'tuo', 'tre'));
console.log(hasTwo('one', 'two', 'three'));
Методы массивов отрабатывают в контексте массивоподобных объектов потому что реализация методов зависит только от числовых индекстов и свойства length
. Обращение к индексам и length
внутри метода происходит через this
.
Преобразование массивоподобного объекта в массив, и работа уже с массивом
Если при работе с массивоподобным объектом хотелось бы использовать методы массивов, можно из элементов массивоподобного объекта создать массив, и продолжать работу с массивом. Создать массив из элементов массивоподобного объекта можно с помощью цикла for
. Тогда функция, определяющая есть ли среди переданных ей аргументов значение 'two' будет выглядеть следующим образом:
function hasTwo() {
var args = [];
for (var i = 0; i < arguments.length; i += 1) {
args.push(arguments[i])
}
return args.indexOf('two') !== -1
}
console.log(hasTwo('uno', 'tuo', 'tre')); // false
console.log(hasTwo('one', 'two', 'three')); // true
Либо создание массива можно выполнить с помощью метода slice
. Если метод вызывать без аргументов, он создает новый массив, в который входят все элементы массива, на котором метод был вызван. Если вызвать метод в контексте массивоподобного объекта, в результате вызова получается массив с элементами из массивоподобного объекта. Тогда функция, определяющая есть ли среди переданных ей аргументов значение 'two' будет выглядеть следующим образом:
function hasTwo() {
var args = Array.prototype.slice.call(arguments)
return args.indexOf('two') !== -1
}
console.log(hasTwo('uno', 'tuo', 'tre')); // false
console.log(hasTwo('one', 'two', 'three')); // true