JavaScript Array includes(): Check if Array Contains a Value
Learn how to use JavaScript's includes() method to check if an array contains a specific value. Covers syntax, examples, and comparison with indexOf().
The includes() method determines whether an array contains a specific value, returning true or false. Introduced in ES2016 (ES7), it provides a cleaner and more intuitive way to check for array membership compared to indexOf().
Understanding includes()
The includes() method performs a case-sensitive search to determine whether an array contains a specific element.
Basic Syntax
// Syntax
array.includes(searchElement);
array.includes(searchElement, fromIndex);
// Parameters:
// - searchElement: The value to search for
// - fromIndex (optional): The position to start searching from
// Basic examples
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
// String array
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana')); // true
console.log(fruits.includes('grape')); // false
// Case sensitivity
const words = ['Hello', 'World'];
console.log(words.includes('hello')); // false (case-sensitive)
console.log(words.includes('Hello')); // true
Using fromIndex Parameter
const arr = [1, 2, 3, 4, 5, 3, 2, 1];
// Start searching from index 3
console.log(arr.includes(2, 3)); // true (found at index 6)
console.log(arr.includes(1, 3)); // true (found at index 7)
// Negative fromIndex (counts from end)
console.log(arr.includes(3, -3)); // false (searches last 3 elements)
console.log(arr.includes(1, -1)); // true (last element is 1)
console.log(arr.includes(2, -3)); // true (found in last 3 elements)
// fromIndex greater than array length
console.log(arr.includes(1, 100)); // false (nothing to search)
// fromIndex as negative number larger than array length
console.log(arr.includes(1, -100)); // true (searches entire array)
// Practical example
const recentSearches = ['javascript', 'python', 'java', 'javascript', 'ruby'];
// Check if 'javascript' appears after first occurrence
const firstIndex = recentSearches.indexOf('javascript');
const appearsAgain = recentSearches.includes('javascript', firstIndex + 1);
console.log(appearsAgain); // true
includes() vs indexOf()
Understanding the differences between includes() and indexOf() helps you choose the right method.
Key Differences
// Return values
const arr = [1, 2, 3, NaN];
// includes() returns boolean
console.log(arr.includes(2)); // true
console.log(arr.includes(4)); // false
// indexOf() returns index or -1
console.log(arr.indexOf(2)); // 1
console.log(arr.indexOf(4)); // -1
// NaN handling - Major difference!
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN)); // -1 (can't find NaN)
// Readability comparison
// Using indexOf() (old way)
if (arr.indexOf(2) !== -1) {
console.log('Found 2');
}
// Using includes() (cleaner)
if (arr.includes(2)) {
console.log('Found 2');
}
// Zero and negative zero
const zeros = [0];
console.log(zeros.includes(-0)); // true
console.log(zeros.indexOf(-0)); // 0 (treats -0 as 0)
When to Use Each
// Use includes() when you need a boolean
const permissions = ['read', 'write', 'delete'];
function hasPermission(permission) {
return permissions.includes(permission);
}
console.log(hasPermission('write')); // true
console.log(hasPermission('admin')); // false
// Use indexOf() when you need the position
const tasks = ['task1', 'task2', 'task3'];
function getTaskPosition(taskName) {
const index = tasks.indexOf(taskName);
if (index !== -1) {
return `Task found at position ${index + 1}`;
}
return 'Task not found';
}
console.log(getTaskPosition('task2')); // "Task found at position 2"
Working with Different Data Types
Primitive Values
// Numbers
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(3.0)); // true (3 === 3.0)
console.log(numbers.includes('3')); // false (different type)
// Strings
const strings = ['hello', 'world', ''];
console.log(strings.includes('hello')); // true
console.log(strings.includes('')); // true (empty string)
console.log(strings.includes(' ')); // false (space !== empty)
// Booleans
const bools = [true, false, true];
console.log(bools.includes(true)); // true
console.log(bools.includes(1)); // false (1 !== true for includes)
// null and undefined
const mixed = [null, undefined, 0, ''];
console.log(mixed.includes(null)); // true
console.log(mixed.includes(undefined)); // true
console.log(mixed.includes()); // true (no argument = undefined)
// Special numeric values
const special = [Infinity, -Infinity, NaN];
console.log(special.includes(Infinity)); // true
console.log(special.includes(NaN)); // true (handles NaN correctly!)
Objects and Arrays
// Object references
const obj1 = { name: 'John' };
const obj2 = { name: 'John' };
const objects = [obj1, { name: 'Jane' }];
console.log(objects.includes(obj1)); // true (same reference)
console.log(objects.includes(obj2)); // false (different object)
console.log(objects.includes({ name: 'Jane' })); // false (different object)
// Array references
const arr1 = [1, 2];
const arrays = [arr1, [3, 4]];
console.log(arrays.includes(arr1)); // true (same reference)
console.log(arrays.includes([1, 2])); // false (different array)
// Solution: Check by value
function includesObject(array, obj) {
return array.some((item) => JSON.stringify(item) === JSON.stringify(obj));
}
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
];
console.log(includesObject(users, { id: 2, name: 'Jane' })); // true
// Deep equality check
function deepIncludes(array, searchElement) {
return array.some((element) => {
if (element === searchElement) return true;
if (typeof element !== 'object' || element === null) return false;
if (typeof searchElement !== 'object' || searchElement === null)
return false;
const keys1 = Object.keys(element);
const keys2 = Object.keys(searchElement);
if (keys1.length !== keys2.length) return false;
return keys1.every((key) =>
deepIncludes([element[key]], searchElement[key])
);
});
}
Practical Use Cases
Form Validation
// Validate allowed values
const validationRules = {
allowedCountries: ['US', 'CA', 'UK', 'AU'],
allowedLanguages: ['en', 'es', 'fr', 'de'],
allowedRoles: ['admin', 'user', 'guest'],
};
function validateForm(formData) {
const errors = [];
if (!validationRules.allowedCountries.includes(formData.country)) {
errors.push('Invalid country selected');
}
if (!validationRules.allowedLanguages.includes(formData.language)) {
errors.push('Unsupported language');
}
if (!validationRules.allowedRoles.includes(formData.role)) {
errors.push('Invalid role');
}
return {
isValid: errors.length === 0,
errors,
};
}
// Email domain whitelist
function isAllowedEmail(email) {
const allowedDomains = ['company.com', 'partner.com', 'subsidiary.com'];
const domain = email.split('@')[1];
return allowedDomains.includes(domain);
}
console.log(isAllowedEmail('user@company.com')); // true
console.log(isAllowedEmail('user@external.com')); // false
Feature Flags and Permissions
// Feature flag system
class FeatureFlags {
constructor() {
this.enabledFeatures = ['dashboard', 'reports', 'analytics'];
this.betaFeatures = ['ai-assistant', 'advanced-search'];
}
isEnabled(feature) {
return this.enabledFeatures.includes(feature);
}
isBetaEnabled(feature, userBetaAccess = false) {
if (userBetaAccess && this.betaFeatures.includes(feature)) {
return true;
}
return this.enabledFeatures.includes(feature);
}
enableFeature(feature) {
if (!this.enabledFeatures.includes(feature)) {
this.enabledFeatures.push(feature);
}
}
disableFeature(feature) {
const index = this.enabledFeatures.indexOf(feature);
if (index !== -1) {
this.enabledFeatures.splice(index, 1);
}
}
}
// Permission checking
class PermissionManager {
constructor(userPermissions) {
this.permissions = userPermissions;
}
can(action) {
return this.permissions.includes(action);
}
canAny(actions) {
return actions.some((action) => this.permissions.includes(action));
}
canAll(actions) {
return actions.every((action) => this.permissions.includes(action));
}
grant(permission) {
if (!this.permissions.includes(permission)) {
this.permissions.push(permission);
}
}
revoke(permission) {
this.permissions = this.permissions.filter((p) => p !== permission);
}
}
// Usage
const userPerms = new PermissionManager(['read', 'write']);
console.log(userPerms.can('read')); // true
console.log(userPerms.can('delete')); // false
console.log(userPerms.canAny(['delete', 'write'])); // true
console.log(userPerms.canAll(['read', 'write'])); // true
Search and Filter Operations
// Multi-select filter
function filterProducts(products, filters) {
return products.filter((product) => {
// Check categories
if (filters.categories.length > 0) {
if (!filters.categories.includes(product.category)) {
return false;
}
}
// Check brands
if (filters.brands.length > 0) {
if (!filters.brands.includes(product.brand)) {
return false;
}
}
// Check price range
if (filters.priceRanges.length > 0) {
const inRange = filters.priceRanges.some((range) => {
const [min, max] = range.split('-').map(Number);
return product.price >= min && product.price <= max;
});
if (!inRange) return false;
}
return true;
});
}
const products = [
{ name: 'Laptop', category: 'Electronics', brand: 'Dell', price: 999 },
{ name: 'Shirt', category: 'Clothing', brand: 'Nike', price: 49 },
{ name: 'Phone', category: 'Electronics', brand: 'Apple', price: 1299 },
];
const filters = {
categories: ['Electronics'],
brands: ['Dell', 'Apple'],
priceRanges: ['500-1000', '1000-1500'],
};
console.log(filterProducts(products, filters));
// Search suggestions
class SearchSuggestions {
constructor() {
this.recentSearches = [];
this.popularSearches = ['javascript', 'python', 'react', 'nodejs'];
}
addSearch(term) {
if (!this.recentSearches.includes(term)) {
this.recentSearches.unshift(term);
if (this.recentSearches.length > 10) {
this.recentSearches.pop();
}
}
}
getSuggestions(input) {
const combined = [
...new Set([...this.recentSearches, ...this.popularSearches]),
];
return combined.filter((term) =>
term.toLowerCase().includes(input.toLowerCase())
);
}
isPopular(term) {
return this.popularSearches.includes(term.toLowerCase());
}
isRecent(term) {
return this.recentSearches.includes(term);
}
}
Advanced Patterns
Custom includes() for Complex Comparisons
// Case-insensitive includes
Array.prototype.includesIgnoreCase = function (searchElement) {
if (typeof searchElement !== 'string') {
return this.includes(searchElement);
}
return this.some(
(element) =>
typeof element === 'string' &&
element.toLowerCase() === searchElement.toLowerCase()
);
};
const names = ['John', 'Jane', 'Bob'];
console.log(names.includesIgnoreCase('JANE')); // true
console.log(names.includesIgnoreCase('jane')); // true
// Partial match includes
Array.prototype.includesPartial = function (searchElement) {
if (typeof searchElement !== 'string') {
return this.includes(searchElement);
}
return this.some(
(element) => typeof element === 'string' && element.includes(searchElement)
);
};
const emails = ['john@example.com', 'jane@test.com', 'bob@example.com'];
console.log(emails.includesPartial('@example.com')); // true
console.log(emails.includesPartial('jane')); // true
// Custom comparison function
function includesWithComparator(array, searchElement, comparator) {
return array.some((element) => comparator(element, searchElement));
}
const dates = [
new Date('2024-01-01'),
new Date('2024-01-15'),
new Date('2024-02-01'),
];
const targetDate = new Date('2024-01-15');
const hasDate = includesWithComparator(
dates,
targetDate,
(a, b) => a.getTime() === b.getTime()
);
console.log(hasDate); // true
Set Operations with includes()
// Array set operations
class ArraySet {
static union(arr1, arr2) {
return [...new Set([...arr1, ...arr2])];
}
static intersection(arr1, arr2) {
return arr1.filter((item) => arr2.includes(item));
}
static difference(arr1, arr2) {
return arr1.filter((item) => !arr2.includes(item));
}
static symmetricDifference(arr1, arr2) {
return [
...arr1.filter((item) => !arr2.includes(item)),
...arr2.filter((item) => !arr1.includes(item)),
];
}
static isSubset(subset, superset) {
return subset.every((item) => superset.includes(item));
}
static isSuperset(superset, subset) {
return subset.every((item) => superset.includes(item));
}
}
// Examples
const set1 = [1, 2, 3, 4];
const set2 = [3, 4, 5, 6];
console.log(ArraySet.union(set1, set2)); // [1, 2, 3, 4, 5, 6]
console.log(ArraySet.intersection(set1, set2)); // [3, 4]
console.log(ArraySet.difference(set1, set2)); // [1, 2]
console.log(ArraySet.symmetricDifference(set1, set2)); // [1, 2, 5, 6]
console.log(ArraySet.isSubset([3, 4], set1)); // true
Performance Optimization
// Caching includes results for large arrays
class CachedArrayChecker {
constructor(array) {
this.array = array;
this.cache = new Map();
// Pre-compute for performance
this.set = new Set(array);
}
includes(searchElement) {
// Check cache first
if (this.cache.has(searchElement)) {
return this.cache.get(searchElement);
}
// Use Set for O(1) lookup
const result = this.set.has(searchElement);
this.cache.set(searchElement, result);
return result;
}
// Batch checking
includesAny(elements) {
return elements.some((el) => this.includes(el));
}
includesAll(elements) {
return elements.every((el) => this.includes(el));
}
// Update array and clear cache
update(newArray) {
this.array = newArray;
this.set = new Set(newArray);
this.cache.clear();
}
}
// Usage with large dataset
const largeArray = Array.from({ length: 10000 }, (_, i) => i);
const checker = new CachedArrayChecker(largeArray);
console.time('First check');
console.log(checker.includes(5000)); // true
console.timeEnd('First check');
console.time('Cached check');
console.log(checker.includes(5000)); // true (from cache)
console.timeEnd('Cached check');
Edge Cases and Gotchas
Special Values
// Empty arrays
const empty = [];
console.log(empty.includes(undefined)); // false
console.log(empty.includes(null)); // false
console.log(empty.includes('')); // false
// Sparse arrays
const sparse = [1, , 3]; // Note the empty slot
console.log(sparse.includes(undefined)); // true (empty slots are undefined)
console.log(sparse.includes(1)); // true
console.log(sparse.includes(2)); // false
// Array with undefined
const withUndefined = [1, undefined, 3];
console.log(withUndefined.includes(undefined)); // true
console.log(withUndefined.includes()); // true (no arg = undefined)
// Type coercion doesn't happen
const mixed = [1, '1', true];
console.log(mixed.includes(1)); // true
console.log(mixed.includes('1')); // true
console.log(mixed.includes(true)); // true
console.log(mixed.includes('true')); // false (no coercion)
Array-like Objects
// includes() doesn't work on array-like objects
const nodeList = document.querySelectorAll('div');
// nodeList.includes(someDiv); // TypeError
// Convert to array first
const nodeArray = Array.from(nodeList);
console.log(nodeArray.includes(someDiv)); // Works
// Or use Array.prototype.includes.call()
const hasDiv = Array.prototype.includes.call(nodeList, someDiv);
// String includes is different
const str = 'hello';
console.log(str.includes('ell')); // true (substring)
console.log(Array.from(str).includes('ell')); // false (array of chars)
console.log(Array.from(str).includes('e')); // true (single char)
Best Practices
1. Use includes() for Readability
// Prefer includes() over indexOf() for boolean checks
// Good
if (allowedValues.includes(userInput)) {
process(userInput);
}
// Less readable
if (allowedValues.indexOf(userInput) !== -1) {
process(userInput);
}
// Even worse
if (~allowedValues.indexOf(userInput)) {
process(userInput);
}
2. Consider Performance for Large Arrays
// For frequent lookups in large arrays, use Set
const largeArray = ['item1', 'item2' /* ... many items ... */];
// Slow for many lookups
function hasItemSlow(item) {
return largeArray.includes(item);
}
// Fast for many lookups
const itemSet = new Set(largeArray);
function hasItemFast(item) {
return itemSet.has(item);
}
3. Handle Edge Cases Explicitly
// Defensive programming
function safeIncludes(array, searchElement) {
if (!Array.isArray(array)) {
return false;
}
// Handle NaN explicitly if needed
if (Number.isNaN(searchElement)) {
return array.some((element) => Number.isNaN(element));
}
return array.includes(searchElement);
}
// Null-safe includes
const nullSafeIncludes = (array, element) => array?.includes(element) ?? false;
4. Document Complex Comparisons
// When checking objects, be clear about reference vs value
class ShoppingCart {
constructor() {
this.items = [];
}
// Checks by reference (same object instance)
containsItem(item) {
return this.items.includes(item);
}
// Checks by product ID (value comparison)
containsProduct(productId) {
return this.items.some((item) => item.productId === productId);
}
}
Conclusion
The includes() method is a simple yet powerful addition to JavaScript's array methods. It provides a clean, readable way to check for array membership, properly handles NaN values, and works well with modern JavaScript patterns. While it's perfect for simple containment checks, remember that it uses strict equality and doesn't work with object comparisons by value. For complex scenarios, combine it with other array methods or use appropriate data structures like Set for better performance.