Я сказал, что программист, который не использует массивы, плохая обезьяна~
Некоторое время назад я взялся за проект, логика неясна, код огромен и избыточен, и начать работу крайне сложно. Основная причина в том, что использование методов массива неэффективно, что приводит к большому количеству мусора в коде.На самом деле, небольшое изменение во многих местах может стать простым, эффективным и элегантным. Поэтому я кратко изложу здесь общие методы и приемы работы с массивами (в основном приемы сводятся~).
Операции с массивами сначала обратите внимание и имейте в видуsplice、sort、reverse
Эти три общих метода являются операциями над самим массивом, которые изменяют сам массив. Другие методы, которые будут меняться сами по себе, — это добавления и удаления.push/pop/unshift/shift
,заполнениеfill
и скопируйте заполнениеcopyWithin
.
Сначала поговорим о распространенных методах работы с массивами, а потом поговорим о недоразумениях.
Общие методы массивов
Во-первых, представьте изображение ленивого человека методом массива, чтобы принести его в жертву небу (кромеArray.keys()/Array.values()/Array.entries()
в принципе все):
Создайте массив вида [1-100]:
При тестировании массива больших объемов данных его можно сгенерировать так:
// fill
const arr = new Array(100).fill(0).map((item, index) => index + 1)
// Array.from() 评论区大佬指出
const arr = Array.from(Array(100), (v, k) => k + 1)
// ... + array.keys() 评论区大佬指出 生成的是0-99的数组
const ary = [...Array(100).keys()]
new Array(100)
сгенерирует массив со 100 пустыми местами, этот массив не может бытьmap(),forEach(), filter(), reduce(), every() ,some()
пройдено, так как слоты пропущены (for of
Не пропускает вакансии, его можно обходить).[...new Array(4)]
Вы можете установить значения по умолчанию для пустых местundefined
, чтобы массив можно было пройти вышеуказанным методом.
Приложение для деструктуризации массива
// 交换变量
[a, b] = [b, a]
[o.a, o.b] = [o.b, o.a]
// 生成剩余数组
const [a, ...rest] = [...'asdf'] // a:'a',rest: ["s", "d", "f"]
Мелкая копия массива
const arr = [1, 2, 3]
const arrClone = [...arr]
// 对象也可以这样浅拷贝
const obj = { a: 1 }
const objClone = { ...obj }
Существует множество методов поверхностного копирования, таких какarr.slice(0, arr.length)/Arror.from(arr)
подожди, но привык...
После оператора вы не захотите использовать другие ~
слияние массивов
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [7, 8, 9]
const arr = [...arr1, ...arr2, ...arr3]
arr1.concat(arr2, arr3)
Слияние также может быть достигнуто, но с использованием...
После оператора вы не захотите использовать другие ~
Дедупликация массива
const arr = [1, 1, 2, 2, 3, 4, 5, 5]
const newArr = [...new Set(arr)]
new Set(arr)
Тип данных, который принимает параметр массива и создает структуру набора. Элементы заданного типа данных не повторяются иArray Iterator
, поэтому вы можете использовать эту функцию для дедупликации.
Пересечение массива
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const duplicatedValues = [...new Set(a)].filter(item => b.includes(item))
duplicatedValues // [3, 4, 5]
вычитание массива
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const diffValues = [...new Set([...a, ...b])].filter(item => !b.includes(item) || !a.includes(item)) // [0, 1, 2, 6, 7, 8]
массив в объект
const arr = [1, 2, 3, 4]
const newObj = {...arr} // {0: 1, 1: 2, 2: 3, 3: 4}
const obj = {0: 0, 1: 1, 2: 2, length: 3}
// 对象转数组不能用展开操作符,因为展开操作符必须用在可迭代对象上
let newArr = [...obj] // Uncaught TypeError: object is not iterable...
// 可以使用Array.form()将类数组对象转为数组
let newArr = Array.from(obj) // [0, 1, 2]
выравнивание массива
const obj = {a: '群主', b: '男群友', c: '女裙友', d: '未知性别'}
const getName = function (item) { return item.includes('群')}
// 方法1
const flatArr = Object.values(obj).flat().filter(item => getName(item))
// 经大佬指点,更加简化(发现自己的抽象能力真的差~)
const flatArr = Object.values(obj).flat().filter(getName)
Для двумерных массивовarray.flat()
, для 3D и вышеarray.flatMap()
.array.flat(2)
Параметрическое слово, такое как 2, может быть передано для указания количества слоев, которые необходимо свести.
Часто используемый обход массива
Массивы обычно перебираются с помощьюforEach、every、some、filter、map、reduce、reduceRight、find、findIndex
Есть много способов добиться того же эффекта. Методы массива нужно не только правильно использовать, но и использовать правильно. Чтобы использовать его хорошо, вы должны знать, когда и как его использовать.
смешанное использование обхода
filter
,map
Возвращаемое значение метода по-прежнему является массивом, поэтому его можно смешивать с другими методами обхода массива. Обратите внимание, что чем больше обходов, тем ниже эффективность~
const arr = [1, 2, 3, 4, 5]
const value = arr
.map(item => item * 3)
.filter(item => item % 2 === 0)
.map(item => item + 1)
.reduce((prev, curr) => prev + curr, 0)
Проверить, все ли элементы массива соответствуют условиям оценки
const arr = [1, 2, 3, 4, 5]
const isAllNum = arr.every(item => typeof item === 'number')
Проверить, есть ли в массиве элементы, соответствующие критериям
const arr = [1, 2, 3, 4, 5]
const hasNum = arr.some(item => typeof item === 'number')
Найдите первый соответствующий элемент/индекс
const arr = [1, 2, 3, 4, 5]
const findItem = arr.find(item => item === 3) // 返回子项
const findIndex = arr.findIndex(item => item === 3) // 返回子项的下标
// 我以后再也不想看见下面这样的代码了😂
let findIndex
arr.find((item, index) => {
if (item === 3) {
findIndex = index
}
})
Ошибки в использовании массивов
Существует много методов работы с массивами, и многие методы могут достичь одного и того же эффекта, поэтому вам следует использовать соответствующий метод в соответствии с вашими потребностями.
Большой причиной генерации мусорного кода является неправильное использование общих методов массивов.Вот следующие моменты, на которые следует обратить внимание:
array.includes() и array.indexOf()
array.includes()
возвращает логическое значение,array.indexOf()
Возвращает индексы дочерних элементов массива.indexOf
Обязательно используйте его, когда требуется значение индекса.
const arr = [1, 2, 3, 4, 5]
// 使用indexOf,需要用到索引值
const index = arr.indexOf(1) // 0
if (~index) { // 若index === -1,~index得到0,判断不成立;若index不为-1,则~index得到非0,判断成立。
arr.spilce(index, 1)
}
// 使用includes,不需要用到索引值
// 此时若用indexOf会造成上下文上的阅读负担:到底其他地方有没有用到这个index?
const isExist = arr.includes(6) // true
if (!isExist) {
arr.push(6)
}
Другой комментатор отметил, чтоarray.indexOf()
НаходитьNaN
не найдется, вернись-1
,array.includes()
может найти, вернутьtrue
~
[NaN].includes(NaN) // true
[NaN].indexOf(NaN) // -1
array.find(), array.findIndex() и array.some()
array.find()
Возвращаемое значение является первым в соответствии с условным массивом,array.findIndex()
Возвращает индекс первого подходящего дочернего элемента массива,array.some()
Возвращает дочерние элементы с составными условиями или без них, если да, возвращаетtrue
, если нет возвратаfalse
. Обратите внимание, что эти три операции являются операциями короткого замыкания, то есть после нахождения квалифицированной обход не будет продолжен.
Используйте, когда вам нужны дочерние элементы массиваarray.find()
; используйте, когда требуется значение индекса дочернего элементаarray.findIndex()
; и если вам нужно только знать, есть ли подпункты, которые соответствуют условиям, используютarray.some()
.
const arr = [{label: '男', value: 0}, {label: '女', value: 1}, {label: '不男不女', value: 2}]
// 使用some
const isExist = arr.some(item => item.value === 2)
if (isExist) {
console.log('哈哈哈找到了')
}
// 使用find
const item = arr.find(item => item.value === 2)
if (item) {
console.log(item.label)
}
// 使用findIndex
const index = arr.findIndex(item => item.value === 2)
if (~index) {
const delItem = arr[index]
arr.splice(index, 1)
console.log(`你删除了${delItem.label}`)
}
Рекомендуется, когда требуются только логические значения и когда элементами массива являются строки или числа.array.some()
:
// 当子包含数字0的时候可能出错
const arr = [0, 1, 2, 3, 4]
// 正确
const isExist = arr.some(item => item === 0)
if (isExist) {
console.log('存在要找的子项,很舒服~')
}
// 错误
const isExist = arr.find(item => item === 0)
if (isExist) { // isExist此时是0,隐式转换为布尔值后是false
console.log('执行不到这里~')
}
// 当子项包含空字符串的时候也可能出错
const arr = ['', 'asdf', 'qwer', '...']
// 正确
const isExist = arr.some(item => item === '')
if (isExist) {
console.log('存在要找的子项,很舒服~')
}
// 错误
const isExist = arr.find(item => item === '')
if (isExist) { // isExist此时是'',隐式转换为布尔值后是false
console.log('执行不到这里~')
}
array.find() и array.filter()
просто нужно знатьarray.filter()
Возвращается массив всех подходящих дочерних элементов, и все массивы будут пройдены; иarray.find()
Возвращается только первый подходящий дочерний элемент, что является операцией короткого замыкания. больше нет примеров~
Используйте структуру данных Set с умом
Поскольку es6 изначально предоставляетSet
структура данных иSet
Он может гарантировать, что подэлементы не повторяются, и его очень удобно преобразовывать с помощью массивов, поэтому его можно использовать напрямую в некоторых сценариях, которые могут включать повторяющиеся добавления.Set
заменятьArray
, чтобы избежать многократного определения того, существует ли подэлемент уже в нескольких местах.
const set = new Set()
set.add(1)
set.add(1)
set.add(1)
set.size // 1
const arr = [...set] // arr: [1]
Мощное сокращение
array.reduce
Перейдите и используйте возвращаемое значение текущей функции обратного вызова в качестве первого параметра следующего выполнения функции обратного вызова.
использоватьarray.reduce
Замена некоторых сценариев, которые необходимо выполнять несколько раз, может значительно повысить эффективность выполнения кода.
- использовать
reduce
вывести число/строку
Предположим, есть массив, в котором каждый элемент состоит из буквы «s», за которой следует число.arr
Теперь узнайте, где находятся самые большие числа :(arr
не ноль)
const arr = ['s0', 's4', 's1', 's2', 's8', 's3']
// 方法1 进行了多次遍历,低效
const newArr = arr.map(item => item.substring(1)).map(item => Number(item))
const maxS = Math.max(...newArr)
// 方法2 一次遍历
const maxS = arr.reduce((prev, cur) => {
const curIndex = Number(cur.replace('s', ''))
return curIndex > prev ? curIndex : prev
}, 0)
- использовать
reduce
вывести массив/объект
const arr = [1, 2, 3, 4, 5]
// 方法1 遍历了两次,效率低
const value = arr.filter(item => item % 2 === 0).map(item => ({ value: item }))
// 方法1 一次遍历,效率高
const value = arr.reduce((prev, curr) => {
return curr % 2 === 0 ? [...prev, { value: curr }] : prev
}, [])
Освойте два вышеупомянутых использования в сочетании с реальными потребностями, вы можете использоватьreduce/reduceRight
Реализуйте всевозможные хитрые трюки.
Пример: использоватьreduce
Выполните следующие действия, чтобы сгенерировать нужную строку HTML:
// 后端返回数据
const data = {
'if _ then s9': [
'作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生',
'作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生',
'作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生'
],
'if C then s4': [
'当有条件时时,结构构件满足要求,要求属于安全性、适用性和耐久性',
'当有条件时时,住宅结构满足要求,要求属于安全性、适用性和耐久性'
]
}
const ifthens = Object.entries(data).reduce((prev, cur) => {
const values = cur[1].reduce((prev, cur) => `${prev}<p>${cur}</p>`, '')
return `
${prev}
<li>
<p>${cur[0]}</p>
${values}
</li>
`
}, '')
const html = `
<ul class="nlp-notify-body">
${ifthens}
</ul>
`
В результате структура html выглядит следующим образом:
<ul class="nlp-notify-body">
<li>
<p>if _ then s9</p>
<p>作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生</p>
<p>作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生</p>
<p>作用属于各种,结构属于住宅,结构能承受作用,作用属于在正常建造和正常使用过程中可能发生</p>
</li>
<li>
<p>if C then s4</p>
<p>当有条件时时,结构构件满足要求,要求属于安全性、适用性和耐久性</p>
<p>当有条件时时,住宅结构满足要求,要求属于安全性、适用性和耐久性</p>
</li>
</ul>
Вот еще альтернативаreverse
функциональный трюк
так какarray.reverse()
Функция сама изменит исходный массив, что ограничивает некоторые сценарии использования. Если мне нужен массив, который не меняет сам массивreverse
Что насчет функций? Унеси это!
const myReverse = (arr = []) => {
return arr.reduceRight((prev, cur) => [...prev, cur], []) // 也可以返回逗号表达式 (prev.push(cur), prev)
}
reduce
Слишком мощный, здесь можно показать только базовое использование. Насколько это мощно? Проверьте этот пост«25 расширенных способов использования Array Reduce, которые вы должны знать»
большой ход
Эй, мимолетные годы неблагоприятны, и любовная сцена сорвана. Многие из моих друзей в мире программирования одиноки. Это урок, который я извлек из своих неудач. Пожалуйста, примите его с улыбкой 😂