Problem
You want to create a generic function to convert array-like objects into arrays (see also recipe 2).
- Array-like objects
- An array-like object is an object, which behaves like an array, but which isn't one.
Array-like objects have a property
lengthand elements can be accessed using indexes, but they typically don't have methods likeforEach()etc. Two popular examples for array-like objects are instances ofNodeListand theargumentsobject.
Ingredients
- the
Arrayprototype - the
slice()method - the
call()method - the
typeofoperator
Directions
-
Given: an array-like object that should be converted.
function someFunction() { var arrayLike = arguments; // An Array-like object var array = toArray(arrayLike); // Our goal: convert it to an array ... array.forEach(function(argument) { // ... so that we can apply array methods. console.log(argument); }); } someFunction(2,3,4,5,6,7); -
Create a function
toArray()that accepts an object.function toArray(object) { } -
Now we need to check if the object is array-like. For that get the
lengthproperty of the object …function toArray(object) { var length = object.length; } -
… and check if the value associated with the
lengthproperty is a number and not less than 0.function toArray(object) { var length = object.length; var isArrayLike = typeof length == 'number' && length >= 0; } -
Optionally, but recommended: extract this code into a separate function
isArrayLike().function isArrayLike(object) { var length = object.length; return typeof length == 'number' && length >= 0; } function toArray(object) { if(isArrayLike(object)) { ... } } -
Back in the
toArray()method: borrow theslice()method to convert the object into an array.function isArrayLike(object) { var length = object.length; return typeof length == 'number' && length >= 0; } function toArray(object) { if(isArrayLike(object)) { return Array.prototype.slice.call(object); } } -
Before checking if the object is array-like it makes sense to check if the object is already an array (using
Array.isArray()).function isArrayLike(object) { var length = object.length; return typeof length == 'number' && length >= 0; } function toArray(object) { if(Array.isArray(object)) { return object; } else if(isArrayLike(object)) { return Array.prototype.slice.call(object); } } -
If the object is neither an array nor array-like: throw an error.
function isArrayLike(object) { var length = object.length; return typeof length == 'number' && length >= 0; } function toArray(object) { if(Array.isArray(object)) { return object; } else if(isArrayLike(object)) { return Array.prototype.slice.call(object); } else { throw new TypeError('Argument could not be converted.'); } } -
Voilá, a tasteful helper function for converting array-like objects into arrays (and one for testing if an object is array-like).
function isArrayLike(object) { var length = object.length; return typeof length == 'number' && length >= 0; } function toArray(object) { if(Array.isArray(object)) { return object; } else if(isArrayLike(object)) { return Array.prototype.slice.call(object); } else { throw new TypeError('Argument could not be converted.'); } } function someFunction() { var arrayLike = arguments; // Array-like object var array = toArray(arrayLike); // Convert to array array.forEach(function(argument) { // Apply array method console.log(argument); }); } someFunction(2,3,4,5,6,7);
Alternative recipes
- Instead of using the
argumentsobject use rest parameters (see also recipe 2).