Checking if it’s an array can be done in several ways: Array.isArray(value)
(recommended), value instanceof Array
, Object.prototype.toString.call(value) === '[object Array]'
or checking the constructor
property. The most reliable way is Array.isArray()
.
Recommended methods:
Array.isArray()
— most reliable and fastestinstanceof Array
— works in most casestoString.call()
— universal for all typesType checking is determining whether a variable is an array. In JavaScript this is important because arrays have special behavior and methods that differ from other objects.
const arr = [1, 2, 3];
const obj = {0: 1, 1: 2, 2: 3, length: 3};
console.log(typeof arr); // "object" ❌ Doesn't help!
console.log(typeof obj); // "object" ❌ Same result!
// typeof doesn't distinguish arrays from objects
console.log(typeof null); // "object" ❌ Even null!
const numbers = [1, 2, 3, 4, 5];
const notArray = {0: 1, 1: 2, length: 2};
console.log(Array.isArray(numbers)); // true
console.log(Array.isArray(notArray)); // false
console.log(Array.isArray(null)); // false
console.log(Array.isArray(undefined)); // false
Advantages:
Disadvantages:
const fruits = ["apple", "banana", "orange"];
const fakeArray = {0: "apple", length: 1};
console.log(fruits instanceof Array); // true
console.log(fakeArray instanceof Array); // false
console.log("string" instanceof Array); // false
Advantages:
Disadvantages:
const data = [1, 2, 3];
const notData = "not array";
console.log(Object.prototype.toString.call(data)); // "[object Array]"
console.log(Object.prototype.toString.call(notData)); // "[object String]"
// Helper function
function isArray(value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
console.log(isArray([1, 2, 3])); // true
console.log(isArray({})); // false
Advantages:
Disadvantages:
const items = [1, 2, 3, 4, 5];
console.log(items.constructor === Array); // true
// But can be fooled
const fake = {};
fake.constructor = Array;
console.log(fake.constructor === Array); // true ❌ False positive!
Disadvantages:
function looksLikeArray(value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.push === 'function' &&
typeof value.pop === 'function';
}
const realArray = [1, 2, 3];
const arrayLike = {length: 3, push: function() {}, pop: function() {}};
console.log(looksLikeArray(realArray)); // true
console.log(looksLikeArray(arrayLike)); // true ❌ False positive!
Disadvantages:
function performanceTest() {
const testArray = [1, 2, 3, 4, 5];
const iterations = 1000000;
// Test 1: Array.isArray()
console.time('Array.isArray');
for (let i = 0; i < iterations; i++) {
Array.isArray(testArray);
}
console.timeEnd('Array.isArray');
// Test 2: instanceof
console.time('instanceof');
for (let i = 0; i < iterations; i++) {
testArray instanceof Array;
}
console.timeEnd('instanceof');
// Test 3: toString.call
console.time('toString.call');
for (let i = 0; i < iterations; i++) {
Object.prototype.toString.call(testArray) === '[object Array]';
}
console.timeEnd('toString.call');
// Test 4: constructor
console.time('constructor');
for (let i = 0; i < iterations; i++) {
testArray.constructor === Array;
}
console.timeEnd('constructor');
}
performanceTest();
Method | Time (ms) | Reliability | Support |
---|---|---|---|
Array.isArray() | ~10 | High | ES5+ |
instanceof Array | ~15 | Medium | All browsers |
toString.call() | ~25 | High | All browsers |
constructor | ~8 | Low | All browsers |
class DataProcessor {
constructor() {
this.data = [];
}
// Safe data addition
addData(input) {
if (Array.isArray(input)) {
this.data.push(...input); // Spread the array
} else {
this.data.push(input); // Add as element
}
}
// Check and process
processInput(value) {
if (Array.isArray(value)) {
return value.map(item => this.processItem(item));
}
return this.processItem(value);
}
processItem(item) {
return typeof item === 'string' ? item.toUpperCase() : item;
}
}
const processor = new DataProcessor();
processor.addData([1, 2, 3]); // Will add 1, 2, 3
processor.addData("single"); // Will add "single"
console.log(processor.data); // [1, 2, 3, "single"]
function forEach(collection, callback) {
// Check if it's an array
if (Array.isArray(collection)) {
collection.forEach(callback);
return;
}
// Check if it's an object with length (array-like)
if (collection && typeof collection.length === 'number') {
for (let i = 0; i < collection.length; i++) {
callback(collection[i], i, collection);
}
return;
}
// Regular object
if (typeof collection === 'object' && collection !== null) {
Object.keys(collection).forEach(key => {
callback(collection[key], key, collection);
});
}
}
// Usage
forEach([1, 2, 3], (item, index) => {
console.log(`Array[${index}]: ${item}`);
});
forEach({a: 1, b: 2}, (value, key) => {
console.log(`Object[${key}]: ${value}`);
});
forEach("hello", (char, index) => {
console.log(`String[${index}]: ${char}`);
});
class TypeChecker {
static getType(value) {
// Check for null and undefined
if (value === null) return 'null';
if (value === undefined) return 'undefined';
// Check for array
if (Array.isArray(value)) return 'array';
// Check for date
if (value instanceof Date) return 'date';
// Check for regular expression
if (value instanceof RegExp) return 'regexp';
// Basic types
return typeof value;
}
static validate(value, expectedType) {
const actualType = this.getType(value);
if (actualType !== expectedType) {
throw new Error(
`Expected ${expectedType}, got ${actualType}`
);
}
return true;
}
static isArrayOf(array, type) {
if (!Array.isArray(array)) {
return false;
}
return array.every(item => this.getType(item) === type);
}
}
// Usage
try {
TypeChecker.validate([1, 2, 3], 'array'); // ✅ Will pass
TypeChecker.validate("string", 'array'); // ❌ Error
} catch (error) {
console.error(error.message);
}
console.log(TypeChecker.isArrayOf([1, 2, 3], 'number')); // true
console.log(TypeChecker.isArrayOf([1, "2", 3], 'number')); // false
const value1 = [];
const value2 = {};
const value3 = null;
console.log(Array.isArray(value1));
console.log(Array.isArray(value2));
console.log(Array.isArray(value3));
const arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3};
console.log(Array.isArray(arrayLike));
console.log(arrayLike instanceof Array);
console.log(typeof arrayLike);
const arr = [1, 2, 3];
arr.constructor = Object;
console.log(Array.isArray(arr));
console.log(arr instanceof Array);
console.log(arr.constructor === Array);
// Typed checking
function processData<T>(data: T | T[]): T[] {
if (Array.isArray(data)) {
return data; // TypeScript knows this is T[]
}
return [data]; // Wrap in array
}
// Usage
const numbers = processData(5); // number[]
const strings = processData(["a", "b"]); // string[]
function handleInput(input) {
// Check and destructure immediately
if (Array.isArray(input)) {
const [first, second, ...rest] = input;
console.log('First:', first);
console.log('Second:', second);
console.log('Rest:', rest);
} else {
console.log('Not an array:', input);
}
}
handleInput([1, 2, 3, 4, 5]);
handleInput("string");
class AsyncArrayProcessor {
async processArrays(data) {
if (!Array.isArray(data)) {
throw new Error('Expected an array');
}
const results = await Promise.all(
data.map(async (item) => {
// Simulate async processing
await new Promise(resolve => setTimeout(resolve, 100));
return item * 2;
})
);
return results;
}
}
const processor = new AsyncArrayProcessor();
// Usage
processor.processArrays([1, 2, 3, 4, 5])
.then(results => console.log('Results:', results))
.catch(error => console.error('Error:', error.message));
// 1. Use Array.isArray() as the main method
function isArray(value) {
return Array.isArray(value); // ✅ Best choice
}
// 2. Create typed checks
function isArrayOf(array, type) {
return Array.isArray(array) &&
array.every(item => typeof item === type);
}
// 3. Document expected types
/**
* Processes an array of numbers
* @param {number[]} numbers - Array of numbers
* @returns {number} Sum of numbers
*/
function sum(numbers) {
if (!Array.isArray(numbers)) {
throw new TypeError('Expected an array of numbers');
}
return numbers.reduce((acc, num) => acc + num, 0);
}
// 4. Use polyfill for old browsers
if (!Array.isArray) {
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
}
// ❌ Don't use typeof for arrays
if (typeof value === 'object') {
// Bad! Objects, null are also object
}
// ❌ Don't rely only on constructor
if (value.constructor === Array) {
// Unreliable! Can be changed
}
// ❌ Don't check only for method presence
if (value && value.push && value.pop) {
// Can give false positives
}
// ❌ Don't use instanceof in iframe
if (value instanceof Array) {
// May not work between frames
}
// ❌ Problem
function processItems(items) {
// Assume it's an array
return items.map(item => item * 2); // Error for NodeList!
}
const elements = document.querySelectorAll('div'); // NodeList
processItems(elements); // TypeError: items.map is not a function
// ✅ Solution
function processItems(items) {
// Check and convert
const array = Array.isArray(items) ? items : Array.from(items);
return array.map(item => item * 2);
}
// ❌ Problem
function getLength(value) {
if (value instanceof Array) {
return value.length; // Error if value = null
}
return 0;
}
console.log(getLength(null)); // TypeError!
// ✅ Solution
function getLength(value) {
if (Array.isArray(value)) {
return value.length; // Safe
}
return 0;
}
// ❌ Problem
function processNestedData(data) {
if (Array.isArray(data)) {
return data.map(item => {
// Forgot to check that item can also be an array
return item.toUpperCase(); // Error if item = []
});
}
}
// ✅ Solution
function processNestedData(data) {
if (Array.isArray(data)) {
return data.map(item => {
if (Array.isArray(item)) {
return processNestedData(item); // Recursion
}
return typeof item === 'string' ? item.toUpperCase() : item;
});
}
return data;
}
Array checking is an important operation in JavaScript with several approaches:
Main methods:
Array.isArray()
— most reliable and fastestinstanceof Array
— works in most casestoString.call()
— universal for all typesconstructor
— unreliable, avoidMethod choice depends on:
Array.isArray()
is fastestArray.isArray()
is most reliableArray.isArray()
in IE8-Recommendations:
// For most cases
Array.isArray(value);
// For old browsers with polyfill
if (!Array.isArray) {
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
}
// For typed checks
function isArrayOf(array, type) {
return Array.isArray(array) && array.every(item => typeof item === type);
}
Understanding the differences between methods is the foundation for reliable type work in JavaScript!
Want more interview preparation articles? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪