Как удалить повторяющиеся элементы массива в JavaScript?
2 года назад·3 мин. на чтение
5 простых способов удаления дубликатов элементов в массиве JavaScript.
Введение
Массивы являются одной из наиболее часто используемых структур данных в JavaScript. Часто массив может содержать дубликаты элементов, которые необходимо удалить для эффективной обработки данных. В этом блоге мы рассмотрим пять способов удаления дубликатов элементов в массиве с помощью JavaScript, ранжированных от наиболее эффективных до наименее эффективных.1. Использование объекта Set
Объект Set
является наиболее эффективным способом удаления дубликатов из массива в JavaScript. Это коллекция уникальных значений, что означает, что она автоматически удаляет дубликаты. Используя spread оператор, мы можем преобразовать объект Set
обратно в массив, в результате чего получается массив, содержащий только уникальные значения. Вот пример:
В этом примере мы сначала определяем массив с повторяющимися значениями. Затем мы создаем новый объектconst arr = [1, 1, 2, 2, 3, 4, 4, 5]; const uniqueArr = [...new Set(arr)]; console.log(uniqueArr); // [1, 2, 3, 4, 5]
Set
с помощью оператора spread (...
). Наконец, мы снова преобразуем объект Set
обратно в массив с помощью оператора spread. Результирующий массив содержит только уникальные значения.
2. Использование метода .filter
Метод .filter
является вторым наиболее эффективным способом удаления дубликатов из массива в JavaScript. Он создает новый массив, который включает только элементы, отвечающие определенному условию, в данном случае элемент появляется в массиве только один раз. Вот пример:
В этом примере мы используем методconst arr = [1, 1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index); console.log(uniqueArr); // [1, 2, 3, 4, 5]
.filter
для создания нового массива uniqueArr
, который включает только элементы, удовлетворяющие условию внутри функции. Условие проверяет, равен ли индекс текущего элемента индексу его первого появления в массиве. Если это так, это означает, что элемент не является дубликатом и может быть включен в новый массив.
3. Использование метода .reduce
Метод .reduce
немного менее эффективен, чем метод .filter
. Он позволяет свести массив к одному значению, применив функцию к каждому элементу массива. В этом случае мы можем использовать .reduce
для создания нового массива, включающего только уникальные значения. Вот пример:
В этом примере мы используем методconst arr = [1, 1, 2, 2, 3, 4, 4, 5]; const uniqueArr = arr.reduce((acc, curr) => { if (!acc.includes(curr)) { acc.push(curr); } return acc; }, []); console.log(uniqueArr); // [1, 2, 3, 4, 5]
.reduce
для итерации по каждому элементу массива и применяем функцию, которая проверяет, находится ли текущий элемент уже в массиве аккумулятора (acc
). Если это не так, мы добавляем его в массив аккумулятора. Метод .reduce
возвращает конечное значение массива аккумулятора, который является массивом, содержащим только уникальные значения.
4. Использование метода .forEach
Метод .forEach
менее эффективен, чем предыдущие методы, но он по-прежнему является жизнеспособным вариантом. Он позволяет перебирать каждый элемент массива и применять к нему функцию. В этом случае мы можем использовать .forEach
для создания нового массива, содержащего только уникальные значения.
Вот пример:
В этом примере мы используем методconst arr = [1, 1, 2, 2, 3, 4, 4, 5]; const uniqueArr = []; arr.forEach((item) => { if (!uniqueArr.includes(item)) { uniqueArr.push(item); } }); console.log(uniqueArr); // [1, 2, 3, 4, 5]
.forEach
для итерации по каждому элементу массива и применения функции, которая проверяет, находится ли уже текущий элемент в массиве uniqueArr
. Если это не так, мы добавляем его в массив uniqueArr
. Результирующий массив содержит только уникальные значения.
5. Использование цикла for
Использование цикла for
является наименее эффективным способом удаления дубликатов из массива. Он требует больше кода и вычислительной мощности, и он не такой лаконичный, как другие методы. Вот пример:
В этом примере мы используем циклconst arr = [1, 1, 2, 2, 3, 4, 4, 5]; const uniqueArr = []; for (let i = 0; i < arr.length; i++) { if (!uniqueArr.includes(arr[i])) { uniqueArr.push(arr[i]); } } console.log(uniqueArr); // [1, 2, 3, 4, 5]
for
для итерации по каждому элементу массива. Проверяем, есть ли текущий элемент в массиве uniqueArr
. Если это не так, мы добавляем его в массив uniqueArr
. Результирующий массив содержит только уникальные значения.
Итоги
Удаление дубликатов из массива является распространенной задачей в JavaScript. В этой статье мы рассмотрели пять различных способов выполнения этой задачи с помощью JavaScript. Каждый метод имеет свои преимущества и недостатки, поэтому вам решать, какой метод наилучшим образом соответствует вашим потребностям. Независимо от того, используется ли объектSet
, метод .filter
, метод .reduce
, метод .forEach
или цикл for
, можно легко удалить дубликаты из массива и более эффективно обрабатывать данные.Хук useContext - как использовать контекст в React?
2 года назад·4 мин. на чтение
useContext - это React хук, который позволяет вам читать и подписываться на контекст из вашего компонента.
API хука useContext
const value = useContext(SomeContext)
useContext(SomeContext)
ВызовитеuseContext
на верхнем уровне вашего компонента для чтения и подписки на контекст.
import { useContext } from 'react'; function MyComponent() { const theme = useContext(ThemeContext); // ...
Параметры
SomeContext
: Контекст, который вы ранее создали с помощьюcreateContext
. Сам контекст не содержит информации, он только представляет тип информации, которую вы можете предоставить или прочитать из компонентов.
Что возвращает useContext
?
useContext
возвращает значение контекста для вызывающего компонента. Оно определяется как значение, переданное ближайшему SomeContext.Provider
, расположенному выше вызывающего компонента в дереве. Если такого провайдера нет, то возвращаемое значение будет значением по умолчанию (defaultValue
), которое вы передали в createContext
для данного контекста. React автоматически перерисовывает компоненты, которые читают некоторый контекст, если он изменяется.
Использование контекста
Передача данных вглубь дерева
ВызовитеuseContext
на верхнем уровне вашего компонента для чтения и подписки на контекст.
import { useContext } from 'react'; function Button() { const theme = useContext(ThemeContext); // ...
useContext
возвращает значение контекста для переданного вами контекста. Чтобы определить значение контекста, React просматривает дерево компонентов и находит ближайший вышеуказанный провайдер контекста для данного контекста.
Чтобы передать контекст кнопке, оберните ее или один из ее родительских компонентов в соответствующий провайдер контекста:
Не имеет значения, сколько слоев компонентов находится между провайдером и кнопкой. Когда кнопка в любом месте формы вызываетfunction MyPage() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ); } function Form() { // ... отрисовывает кнопки внутри себя ... }
useContext(ThemeContext)
, она получит значение "dark"
.
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); }
Обновление данных, переданных через контекст
Часто бывает необходимо, чтобы контекст менялся с течением времени. Чтобы обновить контекст, вам нужно объединить его с состоянием. Объявите переменную state в родительском компоненте и передайте текущее состояние в качестве значения контекста провайдеру.Теперь любая кнопка внутри провайдера будет получать текущее значение темы. Если вы вызоветеunction MyPage() { const [theme, setTheme] = useState('dark'); return ( <ThemeContext.Provider value={theme}> <Form /> <Button onClick={() => { setTheme('light'); }}> Switch to light theme </Button> </ThemeContext.Provider> ); }
setTheme
для обновления значения темы, которое вы передаете провайдеру, все компоненты Button
будут заново отображаться с новым значением "light"
.
Указание значения по умолчанию
Если React не может найти ни одного провайдера данного контекста в родительском дереве, значение контекста, возвращаемое функциейuseContext()
, будет равно значению по умолчанию, которое вы указали при создании контекста:
Значение по умолчанию никогда не изменяется. Если вы хотите обновить контекст, используйте его вместе с состоянием, как описано выше. Часто вместоconst ThemeContext = createContext(null);
null
можно использовать какое-то более значимое значение по умолчанию, например:
Таким образом, если вы случайно отобразите какой-то компонент без соответствующего провайдера, он не сломается. Это также поможет вашим компонентам хорошо работать в тестовой среде без установки большого количества провайдеров в тестах. В приведенном ниже примере кнопка "Toggle theme" всегда светлая, потому что она находится вне любого провайдера контекста темы, а значение контекстной темы по умолчанию -const ThemeContext = createContext('light');
'light'
.
import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext('light'); export default function MyApp() { const [theme, setTheme] = useState('light'); return ( <> <ThemeContext.Provider value={theme}> <Form /> </ThemeContext.Provider> <Button onClick={() => { setTheme(theme === 'dark' ? 'light' : 'dark'); }}> Toggle theme </Button> </> ) } function Form({ children }) { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children, onClick }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className} onClick={onClick}> {children} </button> ); }
Переопределение контекста для части дерева
Вы можете переопределить контекст для части дерева, обернув эту часть в провайдер с другим значением.Вы можете вложить и переопределить провайдеров столько раз, сколько вам нужно.<ThemeContext.Provider value="dark"> ... <ThemeContext.Provider value="light"> <Footer /> </ThemeContext.Provider> ... </ThemeContext.Provider>
Оптимизация повторных рендерингов при передаче объектов и функций
Вы можете передавать любые значения через контекст, включая объекты и функции.Здесь значение контекста - это JavaScript объект с двумя свойствами, одно из которых - функция. Всякий раз, когдаfunction MyApp() { const [currentUser, setCurrentUser] = useState(null); function login(response) { storeCredentials(response.credentials); setCurrentUser(response.user); } return ( <AuthContext.Provider value={{ currentUser, login }}> <Page /> </AuthContext.Provider> ); }
MyApp
ререндерится (например, при обновлении маршрута), это будет другой объект, указывающий на другую функцию, поэтому React также придется перерендерить все компоненты в глубине дерева, которые вызывают useContext(AuthContext)
.
В небольших приложениях это не является проблемой. Однако нет необходимости перерисовывать их, если базовые данные, такие как currentUser
, не изменились. Чтобы помочь React воспользоваться этим фактом, вы можете обернуть функцию входа в систему в useCallback
и обернуть создание объекта в useMemo
.
В результате этого изменения, даже еслиimport { useCallback, useMemo } from 'react'; function MyApp() { const [currentUser, setCurrentUser] = useState(null); const login = useCallback((response) => { storeCredentials(response.credentials); setCurrentUser(response.user); }, []); const contextValue = useMemo(() => ({ currentUser, login }), [currentUser, login]); return ( <AuthContext.Provider value={contextValue}> <Page /> </AuthContext.Provider> ); }
MyApp
потребуется повторный рендеринг, компонентам, вызывающим useContext(AuthContext)
, не потребуется повторный рендеринг, если только currentUser
не изменился.