Проверить что это массив можно несколькими способами: Array.isArray(value)
(рекомендуемый), value instanceof Array
, Object.prototype.toString.call(value) === '[object Array]'
или проверка свойства constructor
. Самый надёжный способ — Array.isArray()
.
Рекомендуемые методы:
Array.isArray()
— самый надёжный и быстрыйinstanceof Array
— работает в большинстве случаевtoString.call()
— универсальный для всех типовПроверка типа данных — это определение того, является ли переменная массивом. В JavaScript это важно, поскольку массивы имеют особое поведение и методы, отличные от других объектов.
const arr = [1, 2, 3];
const obj = {0: 1, 1: 2, 2: 3, length: 3};
console.log(typeof arr); // "object" ❌ Не помогает!
console.log(typeof obj); // "object" ❌ Тот же результат!
// typeof не различает массивы и объекты
console.log(typeof null); // "object" ❌ Даже 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
Преимущества:
Недостатки:
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
Преимущества:
Недостатки:
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]"
// Функция-помощник
function isArray(value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
console.log(isArray([1, 2, 3])); // true
console.log(isArray({})); // false
Преимущества:
Недостатки:
const items = [1, 2, 3, 4, 5];
console.log(items.constructor === Array); // true
// Но может быть обманута
const fake = {};
fake.constructor = Array;
console.log(fake.constructor === Array); // true ❌ Ложный результат!
Недостатки:
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 ❌ Ложный результат!
Недостатки:
function performanceTest() {
const testArray = [1, 2, 3, 4, 5];
const iterations = 1000000;
// Тест 1: Array.isArray()
console.time('Array.isArray');
for (let i = 0; i < iterations; i++) {
Array.isArray(testArray);
}
console.timeEnd('Array.isArray');
// Тест 2: instanceof
console.time('instanceof');
for (let i = 0; i < iterations; i++) {
testArray instanceof Array;
}
console.timeEnd('instanceof');
// Тест 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');
// Тест 4: constructor
console.time('constructor');
for (let i = 0; i < iterations; i++) {
testArray.constructor === Array;
}
console.timeEnd('constructor');
}
performanceTest();
Метод | Время (мс) | Надёжность | Поддержка |
---|---|---|---|
Array.isArray() | ~10 | Высокая | ES5+ |
instanceof Array | ~15 | Средняя | Все браузеры |
toString.call() | ~25 | Высокая | Все браузеры |
constructor | ~8 | Низкая | Все браузеры |
class DataProcessor {
constructor() {
this.data = [];
}
// Безопасное добавление данных
addData(input) {
if (Array.isArray(input)) {
this.data.push(...input); // Разворачиваем массив
} else {
this.data.push(input); // Добавляем как элемент
}
}
// Проверка и обработка
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]); // Добавит 1, 2, 3
processor.addData("single"); // Добавит "single"
console.log(processor.data); // [1, 2, 3, "single"]
function forEach(collection, callback) {
// Проверяем что это массив
if (Array.isArray(collection)) {
collection.forEach(callback);
return;
}
// Проверяем что это объект с length (array-like)
if (collection && typeof collection.length === 'number') {
for (let i = 0; i < collection.length; i++) {
callback(collection[i], i, collection);
}
return;
}
// Обычный объект
if (typeof collection === 'object' && collection !== null) {
Object.keys(collection).forEach(key => {
callback(collection[key], key, collection);
});
}
}
// Использование
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) {
// Проверка на null и undefined
if (value === null) return 'null';
if (value === undefined) return 'undefined';
// Проверка на массив
if (Array.isArray(value)) return 'array';
// Проверка на дату
if (value instanceof Date) return 'date';
// Проверка на регулярное выражение
if (value instanceof RegExp) return 'regexp';
// Базовые типы
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);
}
}
// Использование
try {
TypeChecker.validate([1, 2, 3], 'array'); // ✅ Пройдёт
TypeChecker.validate("string", 'array'); // ❌ Ошибка
} 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);
// Типизированная проверка
function processData<T>(data: T | T[]): T[] {
if (Array.isArray(data)) {
return data; // TypeScript знает что это T[]
}
return [data]; // Оборачиваем в массив
}
// Использование
const numbers = processData(5); // number[]
const strings = processData(["a", "b"]); // string[]
function handleInput(input) {
// Проверяем и сразу деструктурируем
if (Array.isArray(input)) {
const [first, second, ...rest] = input;
console.log('Первый:', first);
console.log('Второй:', second);
console.log('Остальные:', rest);
} else {
console.log('Не массив:', input);
}
}
handleInput([1, 2, 3, 4, 5]);
handleInput("строка");
class AsyncArrayProcessor {
async processArrays(data) {
if (!Array.isArray(data)) {
throw new Error('Ожидался массив');
}
const results = await Promise.all(
data.map(async (item) => {
// Имитация асинхронной обработки
await new Promise(resolve => setTimeout(resolve, 100));
return item * 2;
})
);
return results;
}
}
const processor = new AsyncArrayProcessor();
// Использование
processor.processArrays([1, 2, 3, 4, 5])
.then(results => console.log('Результаты:', results))
.catch(error => console.error('Ошибка:', error.message));
// 1. Используйте Array.isArray() как основной метод
function isArray(value) {
return Array.isArray(value); // ✅ Лучший выбор
}
// 2. Создавайте типизированные проверки
function isArrayOf(array, type) {
return Array.isArray(array) &&
array.every(item => typeof item === type);
}
// 3. Документируйте ожидаемые типы
/**
* Обрабатывает массив чисел
* @param {number[]} numbers - Массив чисел
* @returns {number} Сумма чисел
*/
function sum(numbers) {
if (!Array.isArray(numbers)) {
throw new TypeError('Ожидался массив чисел');
}
return numbers.reduce((acc, num) => acc + num, 0);
}
// 4. Используйте полифилл для старых браузеров
if (!Array.isArray) {
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
}
// ❌ Не используйте typeof для массивов
if (typeof value === 'object') {
// Плохо! Объекты, null тоже object
}
// ❌ Не полагайтесь только на constructor
if (value.constructor === Array) {
// Ненадёжно! Может быть изменён
}
// ❌ Не проверяйте только наличие методов
if (value && value.push && value.pop) {
// Может дать ложные срабатывания
}
// ❌ Не используйте instanceof в iframe
if (value instanceof Array) {
// Может не работать между фреймами
}
// ❌ Проблема
function processItems(items) {
// Предполагаем что это массив
return items.map(item => item * 2); // Ошибка для NodeList!
}
const elements = document.querySelectorAll('div'); // NodeList
processItems(elements); // TypeError: items.map is not a function
// ✅ Решение
function processItems(items) {
// Проверяем и конвертируем
const array = Array.isArray(items) ? items : Array.from(items);
return array.map(item => item * 2);
}
// ❌ Проблема
function getLength(value) {
if (value instanceof Array) {
return value.length; // Ошибка если value = null
}
return 0;
}
console.log(getLength(null)); // TypeError!
// ✅ Решение
function getLength(value) {
if (Array.isArray(value)) {
return value.length; // Безопасно
}
return 0;
}
// ❌ Проблема
function processNestedData(data) {
if (Array.isArray(data)) {
return data.map(item => {
// Забыли проверить что item тоже может быть массивом
return item.toUpperCase(); // Ошибка если item = []
});
}
}
// ✅ Решение
function processNestedData(data) {
if (Array.isArray(data)) {
return data.map(item => {
if (Array.isArray(item)) {
return processNestedData(item); // Рекурсия
}
return typeof item === 'string' ? item.toUpperCase() : item;
});
}
return data;
}
Проверка массивов — это важная операция в JavaScript с несколькими подходами:
Основные методы:
Array.isArray()
— самый надёжный и быстрыйinstanceof Array
— работает в большинстве случаевtoString.call()
— универсальный для всех типовconstructor
— ненадёжный, избегайтеВыбор метода зависит от:
Array.isArray()
самый быстрыйArray.isArray()
самый надёжныйArray.isArray()
в IE8-Рекомендации:
// Для большинства случаев
Array.isArray(value);
// Для старых браузеров с полифиллом
if (!Array.isArray) {
Array.isArray = function(value) {
return Object.prototype.toString.call(value) === '[object Array]';
};
}
// Для типизированных проверок
function isArrayOf(array, type) {
return Array.isArray(array) && array.every(item => typeof item === type);
}
Понимание различий между методами — это основа для надёжной работы с типами в JavaScript!
Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice(@AleksandrEmolov_EasyAdvice), добавляйте сайт в закладки и совершенствуйтесь каждый день 💪