JavaScript has "Array-like Objects", which are Object representations of Arrays with a length property. For example:
var realArray = ['a', 'b', 'c'];
var arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
Common examples of Array-like Objects are the arguments
object in functions and HTMLCollection
or NodeList
objects returned from methods like document.getElementsByTagName
or document.querySelectorAll
.
However, one key difference between Arrays and Array-like Objects is that Array-like objects inherit from Object.prototype
instead of Array.prototype
. This means that Array-like Objects can't access common Array prototype methods like forEach()
, push()
, map()
, filter()
, and slice()
:
var parent = document.getElementById('myDropdown');
var desiredOption = parent.querySelector('option[value="desired"]');
var domList = parent.children;
domList.indexOf(desiredOption); // Error! indexOf is not defined.
domList.forEach(function() {
arguments.map(/* Stuff here */) // Error! map is not defined.
}); // Error! forEach is not defined.
function func() {
console.log(arguments);
}
func(1, 2, 3); // → [1, 2, 3]
Array.from
:const arrayLike = {
0: 'Value 0',
1: 'Value 1',
length: 2
};
arrayLike.forEach(value => {/* Do something */}); // Errors
const realArray = Array.from(arrayLike);
realArray.forEach(value => {/* Do something */}); // Works
for...of
:var realArray = [];
for(const element of arrayLike) {
realArray.append(element);
}
[...arrayLike]
Object.values
:var realArray = Object.values(arrayLike);
Object.keys
:var realArray = Object
.keys(arrayLike)
.map((key) => arrayLike[key]);
Use Array.prototype.slice
like so:
var arrayLike = {
0: 'Value 0',
1: 'Value 1',
length: 2
};
var realArray = Array.prototype.slice.call(arrayLike);
realArray = [].slice.call(arrayLike); // Shorter version
realArray.indexOf('Value 1'); // Wow! this works
You can also use Function.prototype.call
to call Array.prototype
methods on Array-like objects directly, without converting them:
var domList = document.querySelectorAll('#myDropdown option');
domList.forEach(function() {
// Do stuff
}); // Error! forEach is not defined.
Array.prototype.forEach.call(domList, function() {
// Do stuff
}); // Wow! this works
You can also use [].method.bind( arrayLikeObject )
to borrow array methods and glom them on to your object:
var arrayLike = {
0: 'Value 0',
1: 'Value 1',
length: 2
};
arrayLike.forEach(function() {
// Do stuff
}); // Error! forEach is not defined.
[].forEach.bind(arrayLike)(function(val){
// Do stuff with val
}); // Wow! this works
In ES6, while using Array.from
, we can specify a map function that returns a mapped value for the new array being created.
Array.from(domList, element => element.tagName); // Creates an array of tagName's
See Arrays are Objects for a detailed analysis.