Как получить все уникальные значения из массива в JavaScript (удаление дубликатов)
Использование Set — самый простой и современный способ
Объект Set в JavaScript автоматически хранит только уникальные значения. Чтобы получить массив уникальных элементов, просто преобразуйте Set обратно в массив.
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'kiwi', 'orange'];
const uniqueFruits = [...new Set(fruits)];
console.log(uniqueFruits); // ['apple', 'banana', 'orange', 'kiwi']
Объяснение:
new Set(fruits)создаёт коллекцию, где каждый элемент встречается только один раз.- Оператор
...(spread) разворачивает Set в элементы нового массива. - Этот способ работает для примитивных типов (строки, числа, булевы значения, null, undefined).
- Порядок элементов сохраняется в порядке первого появления.
Обработка объектов и смешанных типов
Если массив содержит объекты или смешанные типы, Set сравнивает по ссылке, а не по содержимому. Для глубокого сравнения используйте JSON.stringify или библиотеки типа Lodash:
const arr = [{id: 1}, {id: 1}, {id: 2}];
const unique = [...new Set(arr.map(item => JSON.stringify(item)))].map(str => JSON.parse(str));
console.log(unique); // [{id: 1}, {id: 2}]
Внимание: этот метод не работает, если объекты содержат функции или циклические ссылки.
Альтернативные методы (для старых браузеров или специфических задач)
Метод filter + indexOf:
const unique = fruits.filter((item, index) => fruits.indexOf(item) === index);
Этот способ медленнее на больших массивах, так как indexOf проходит по массиву каждый раз.
Метод reduce:
const unique = fruits.reduce((acc, item) => {
if (!acc.includes(item)) acc.push(item);
return acc;
}, []);
Работает, но тоже не оптимален для больших данных.
Производительность для больших массивов
Для массивов с 10 000+ элементов Set значительно быстрее (O(n) против O(n²) у filter + indexOf). Вот пример замеров:
// Создаём большой массив с дубликатами
const bigArray = Array.from({ length: 10000 }, (_, i) => i % 1000);
console.time('Set');
const uniqueSet = [...new Set(bigArray)];
console.timeEnd('Set'); // ~0.1ms
console.time('Filter');
const uniqueFilter = bigArray.filter((item, index) => bigArray.indexOf(item) === index);
console.timeEnd('Filter'); // ~50ms (в 500 раз медленнее!)
Модификация исходного массива
Хотя обычно рекомендуется создавать новый массив, вы можете изменить исходный:
const arr = [1, 2, 1, 3, 2];
arr.splice(0, arr.length, ...new Set(arr));
console.log(arr); // [1, 2, 3]
Итог: для 99% случаев используйте [...new Set(array)] — это чисто, быстро и читаемо.
Использование Object (для совместимости со старыми браузерами)
Если вам нужно поддерживать очень старые браузеры (IE11 и ниже), где Set может отсутствовать, можно использовать объект в качестве хеш-таблицы:
function getUnique(arr) {
const seen = {};
const result = [];
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (!seen[item]) {
seen[item] = true;
result.push(item);
}
}
return result;
}
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'kiwi', 'orange'];
console.log(getUnique(fruits)); // ['apple', 'banana', 'orange', 'kiwi']
Этот метод:
- Работает за O(n) — быстрее, чем
filter + indexOf. - Не требует дополнительных полифиллов.
- Но есть нюанс: ключи объекта преобразуются в строки, поэтому числа и строки могут смешиваться (например,
1и'1'будут считаться одинаковыми).
Для чисел и строк этот способ надёжен. Для объектов используйте Map вместо объекта — он сохраняет тип ключа:
function getUniqueWithMap(arr) {
const seen = new Map();
const result = [];
for (const item of arr) {
if (!seen.has(item)) {
seen.set(item, true);
result.push(item);
}
}
return result;
}
Этот вариант полностью аналогичен Set по производительности, но может быть полезен, если нужно дополнительно хранить какие-то данные для каждого уникального элемента.