история
Ведущий 💬: «Оказывается, есть изменение требований к проекту, и вам нужно его изменить. Изменений не много. Это должно быть очень скоро».
Ersheng💬: «Хорошо👌, я сначала посмотрю».
Эршэн, у которого было неспокойно на душе, открыл старый проект. Он не знал, не читал ли он его. Когда он увидел его, то был в шоке. Код проекта был, вероятно, таким:
Одна статья Миллениум окропляетКаждая строка кода плотная
Пишите все, что хотите, за один раз
неорганизованный беспорядок
Повторяющийся код аккуратен и красив
Нин пишет много раз и никогда не инкапсулирует
Глобальные переменные летают
Если вы хотите использовать его, используйте его с неба
Имена переменных все в порядке
a1 , a2 , a3 , a4
просто используйтеfor
+if
утверждение
Реализовать все без страха
Умереть здесь и умереть там
Мультиплексирование — это прямое копирование
Берегите чернила, как золото, и не пишите заметок
Я не понимаю, это чужое дело
Перед лицом этих беспорядочных кодов Эршэн расплакалась😭.
Во взрослом мире нет простого слова, Эршэн вытер слезы и начал осторожно менять код.
наконец90%
время, потраченное на чтение кода,10%
Время, потраченное на исправления, похоже на завершение проекта домино, и чувство выполненного долга возникает спонтанно.
Итак, Ersheng с гордостью написал в отчете о работе: Сегодня измените XXX (небольшая функция), примечания: исходный код не легко читать.
Когда руководитель видит отчет о работе, его внутренняя активность: «Небольшая функция так долго менялась?новичокЭто было написано, но было сказано, что это было нелегко прочитать и понять.Похоже, что способности этого сотрудника не хороши. "
предисловие
- Цель статьи: Помочь каждому писать код с высокой читабельностью и ремонтопригодностью 😁
- Подходит для людей: младшего персонала и друзей, которые хотят, чтобы их товарищи по команде хорошо писали код
- Время чтения: зависит от человека, всего
4000+
Words, если не можете дочитать, нажмите на подборку 👍⭐
3 аспекта
Подготовить данные
// 鼠笼🐀🐀🐀
const mouseList = [
{ id: 'm01', name: '小白鼠', type: '0' },
{ id: 'm02', name: '小黑鼠', type: '4' },
{ id: 'm03', name: '小红鼠', type: '5' },
{ id: 'm04', name: '小橙鼠', type: '3' },
{ id: 'm05', name: '小黄鼠', type: '1' },
{ id: 'm06', name: '小青鼠', type: '1' },
{ id: 'm07', name: '小蓝鼠', type: '2' },
{ id: 'm08', name: '小绿鼠', type: '2', cap:{} },
{ id: 'm09', name: '小紫鼠', type: '5' },
]
// 类型对照表
const typeMap = {
'0': '家鼠',
'1': '田鼠',
'2': '竹鼠',
'3': '松鼠',
'4': '米老鼠',
'5': '快乐番薯'
}
Аспект 1: показать намерение
Четко скажите читателю, что вы делаете
Ниже приведен пример
📄Спрос
Ты иди 👉скажи мне вежливо小绿鼠
, его жена изменяла.
✍ Реализация
var flag = false
for (var i = 0; i < mouseList.length; i++) {
if (mouseList[i].name == '小绿鼠') {
mouseList[i].cap.color = 'green'
flag = true
break
}
}
if (flag) {
console.log('我已经告诉他了')
} else {
console.warn('没有找到小绿鼠')
}
🔍Анализ
Теперь давайте проанализируем, что делает приведенный выше код:
- определить переменную
flag
, значение по умолчаниюfalse
- правильно
mouseList
траверс - Если элемент массива
name
да小绿鼠
- данный этому элементу массива
cap
атрибутcolor
уступка имущества - поместите переменную
flag
переназначатьtrue
- завершить цикл
- пройти через
flag
Определить, найдено ли оно, дать подсказку
Как видите, нам нужно прочитать весь фрагмент кода, чтобы понять, что он делает, потому что первое, что мы видим, этоfor
+if
, мы знаем только отсюда, что遍历
+判断
, без более четкого намерения.
🛠Оптимизировано
Вот 3 способа сделать цель вашего кода более явной:
- пишите комментарии напрямую
Добавьте комментарии к двум небольшим фрагментам кода соответственно:
- Найдите одну из мышей по имени
小绿鼠
мышь, помоги ему покрасить шляпу в зеленый цвет - Напоминание, когда все сделано
Писать комментарии просто и грубо, но очень эффективно. Однако независимо от того, пишет ли автор аннотацию или читатель аннотацию, это требует времени, поэтому, если это простая функция, аннотация не нужна.
- имя внутри сообщения
Комментарии можно опускать или не писать, но от нейминга вообще никуда не деться.Поскольку так называемый нестандартный нейминг, тиммейты плачут в две строчки, слепой нейминг вредит не только тиммейтам, но и самим себе, которые смотрят на код в будущем .
Исходный код написан какflag
var flag = false
Теперь мы меняем его на это
let isFound = false
У такой записи есть 3 преимущества:
- использовать
ES6
изlet
вместоconst
, указывая на то, что в будущем я будупереназначать,а такжеvar
просто простое заявление -
is
Начало переменной равноBoolean
Тип, если группа разных переменных смешивается вместе в следующем, ее можно распознать с первого взгляда. -
isFound
означает是否找到
,этоfound
Как только она выходит, читатели сразу узнают авторанамерение найти что-либо
found это причастие прошедшего времени от find
Итак, просто посмотрите наlet isFound = false
, не глядя на приведенный ниже код, мы можем сделать вывод, что автор ищет цель,isFound
Он используется как индикатор того, найдена ли цель.Если цель найдена, должно бытьisFound = true
Код появляется
- использовать функцию
Смысл использования функций здесь заключается в том, чтобы инкапсулировать несущественный контент в функции, оставив только основную информацию и выделив намерение через основную информацию.
Перед инкапсуляцией давайте разобьем логику кода на несколько более подробных.найти цельа такжедействовать на цельразделить на два этапа, следующиенайти цельИнкапсулированные в функцию, сначала извлеките элементы:
- Область применения (где найти)
- Объективное описание (что искать)
- Количество (найдите несколько)
- результат (не найдено)
Используйте это, чтобы инкапсулировать функцию
/**
* 数组里面找元素
* @param {array} array 范围
* @param {function} callback 目标描述
* @param {number} count 数量
* @return {array} 结果
*/
function arrayFindItem(array, callback, count) {
const result = []
let _count = 0
for (let i = 0; i < array.length; i++) {
if (callback(array[i])) {
_count++
result.push(array[i])
if (_count === count) {
return result
}
}
}
return result
}
затем используйте его
const result = arrayFindItem(mouseList, function(mouse) {
return mouse.name === '小绿鼠'
}, 1)
Таким образом, остальная информация в коде понятна:
- поведение:
arrayFindItem
найти элемент в массиве - Где найти:
mouseList
- Что искать:
function(mouse) { return mouse.name === '小绿鼠' }
- Найдите несколько: 1
- Вы нашли:
result
Хотя это гораздо яснее, предпосылка состоит в том, чтоarrayFindItem
Параметры и возвращаемые значения хорошо понятны, и в этом случае есть лучшее решение:Array.prototype.find
const result = mouseList.find(function(mouse) {
return mouse.name === '小绿鼠'
})
Так как этоes6
Метод массива в спецификации, так что все уже очень хорошо знают его поведение, и дополнительных затрат на чтение нет.
Аспект 2: Разделение кода
Все нужно делать по частям, а код писать по частям.
📄Спрос
- Возьмите сырую крысу в клетку и приготовьте ее следующим образом:
- Бамбуковая крыса -> жареная
- домовые мыши и полевки -> вареные
- Сладкий картофель -> Гриль на углях🔥
- Приготовь на ужин, сегодня вечером хочу съесть 🍽
✍ Реализация
Код, который может написать новичок
var dinnerList = []
for (var i = 0; i < mouseList.length; i++) {
if (mouseList[i].isRaw != true) {
if (mouseList[i].type === '2') {
// 宽油竹鼠
mouseList[i].recipe = '油炸配方'
mouseList[i].newName = '油炸' + mouseList[i].name
// ...被省略的油炸的其他操作
mouseList[i].isRaw = true
dinnerList.push(mouseList[i])
} else if (mouseList[i].type === '0' || mouseList[i].type === '1') {
// 水煮家鼠 + 田鼠
mouseList[i].recipe = '水煮配方'
mouseList[i].newName = '水煮' + mouseList[i].name
// ...被省略的水煮的其他操作
mouseList[i].isRaw = true
dinnerList.push(mouseList[i])
} else if (mouseList[i].type === '5') {
// 烤番薯
mouseList[i].recipe = '碳烤配方'
mouseList[i].newName = '碳烤' + mouseList[i].name
// ...被省略的碳烤的其他操作
mouseList[i].isRaw = true
dinnerList.push(mouseList[i])
}
}
}
console.log(dinnerList)
🔍Анализ
- определить массив
dinnerList
- траверс
mouseList
- найти все свойства
isRaw
даtrue
элемент массива - На основании 3, по признаку
type
разные, выполнять разные операции-
type
да2
==> жарка -
type
да0
или1
==> Операция кипячения -
type
да5
==> Угольный гриль
-
Очевидно, процесс приготовления пишите прямо вfor
Цикл сделает цикл слишком длинным, что не способствует чтению, поэтому его следует разделить.
🛠Оптимизировано
Итак, давайте сделаем первый шаг и разделим способ приготовления
/* ****** 这里是烹饪的方法们 ****** */
function fry(mouse) {
mouse.recipe = '油炸配方'
mouse.newName = '油炸' + mouse.name
// ...被省略的油炸的其他操作
mouse.isRaw = true
}
function boil(mouse) {
mouse.recipe = '水煮配方'
mouse.newName = '水煮' + mouse.name
// ...被省略的水煮的其他操作
mouse.isRaw = true
}
function roast(mouse) {
mouse.recipe = '碳烤配方'
mouse.newName = '碳烤' + mouse.name
// ...被省略的碳烤的其他操作
mouse.isRaw = true
}
Итак, у нас есть 3 метода приготовления, соедините их, чтобы аннотировать, это понятно и легко поддерживать.
Предполагая, что текущим требованием является изменение определенного метода приготовления, нам нужно только найти метод и изменить внутреннюю реализацию метода, и это будет сделано, даже не беспокоясь о том, где метод вызывается.
Не закончено, затем завершите код
var dinnerList = []
for (var i = 0; i < mouseList.length; i++) {
if (mouseList[i].isRaw != true) {
if (mouseList[i].type === '2') {
fry(mouseList[i]) // 宽油竹鼠
dinnerList.push(mouseList[i])
} else if (mouseList[i].type === '0' || mouseList[i].type === '1') {
boil(mouseList[i]) // 水煮家鼠 + 田鼠
dinnerList.push(mouseList[i])
} else if (mouseList[i].type === '5') {
roast(mouseList[i]) // 烤番薯
dinnerList.push(mouseList[i])
}
}
}
console.log(dinnerList)
Этот цикл появляетсяif... else if... else if...
, а объектом суждения являетсяtype
, что доказывает, что есть логика, которую можно разделить.
Ознакомьтесь с нашими первоначальными требованиями
- Бамбуковая крыса -> Широкая масляная бамбуковая крыса
- домовые мыши и полевки -> вареные
- Сладкий картофель -> жареный на углях
Пусть логика куска кода близка к требованиям, тогда либочитаемость кодаещеРеагировать на меняющиеся требованияспособность поднимется до уровня.
Следующим шагом является преобразование требований в код: Левая часть заменена на тип, правая часть заменена на функцию, предварительный вариант:
условие | действовать |
---|---|
type да2
|
операция жарки |
type да0 или1
|
Операция кипячения |
type да5
|
Работа на угольном гриле |
Затем замените его кодовой записью:
type | cookFn |
---|---|
2 |
fry() |
0 || 1 |
boil() |
5 |
roast() |
В этот момент вы обнаружите, что эта корреспонденцияkey
=> value
,key
это мышьtype
, value
это способ приготовленияcookFn
, поэтому мы должны использовать объекты для хранения корреспонденции
// 老鼠烹饪方法映射表
const mouseCookFnMap = {
// type: cookFn
'0': boil,
'1': boil,
'2': fry,
'5': roast
}
Идеально! Если у вас обсессивно-компульсивное расстройство, вы также можете заполнить все типы, как это
// 老鼠烹饪方法映射表(强迫症版)
const mouseCookFnMapIllVer = {
// type: cookFn
'0': boil,
'1': boil,
'2': fry,
'3': undefined, // 未指定烹饪方法
'4': undefined,
'5': roast
}
Используйте его, как только вы его напишете
var dinnerList = []
for (var i = 0; i < mouseList.length; i++) {
if (mouseList[i].isRaw != true) {
var cookFn = mouseCookFnMap[mouseList[i].type]
if (cookFn) { // cookFn !== undefined
cookFn(mouseList[i])
dinnerList.push(mouseList[i])
}
}
}
console.log(dinnerList)
В это время вы получаете изменение спроса: «Бамбуковая крыса с широким маслом слишком дорога, поменяйте ее на гриль на углях для меня».
просто поставь'2': fry,
изменить на'2': roast,
Просто 🆗.
и, используяТаблица отношений сопоставленияНекоторые сценарии с более сложными требованиями могут быть легко обработаны.
Например宽油竹鼠
, На самом деле, это не может быть сделано путем жарки.Шкура и мясо бамбуковой крысы относительно толстые, и она долго варится, поэтому для竹鼠
, нужно сначала油炸
Опять таки焖煮
.
На данный момент таблица сопоставленияvalue
Это не просто один метод, это должно быть несколько методов, и они должны быть упорядочены, очевидно, их можно хранить в массиве:
// 加一个`焖煮方法`
function braise(mouse) {
// ... 省略的焖煮方法具体实现
}
// 老鼠烹饪方法映射表加强版
const mouseCookFnMapPlus = {
// type: cookFnArray
'0': [boil],
'1': [boil],
'2': [fry, braise],
'5': [roast]
}
При использовании метод будет вызываться напрямую
cookFn(mouseList[i])
Изменить для обхода массива и последовательного вызова
cookFnArray.forEach(cookFn => cookFn(mouseList(i)))
Я действительно не хочу писать здесьfor
зацикленный, б/уforEach
, следующее посоветует вам не писать как можно большеfor
цикл
Аспект 3: Устранение избыточности
Этот аспект в основном обсуждает, как удалить избыточность в коде на грамматическом уровне.Конкретный метод заключается в том, чтобы найти части (в основном переменные) в коде, которые не имеют отношения к теме, и попытаться удалить их.
Здесь не будет добавлено никаких новых требований, просто возьмите приведенный выше пример и используйте его.
Стрелочные функции ➡
ES6
стрелочная функцияЕсть два преимущества:
- изменить функцию
this
направление
В прошлом для преобразования внутреннегоthis
Укажите на внешнюю область, основным методом является
var that = this
// or
var self = this
Серьезно, см.that
У меня большая голова 😰, определите функцию перед запуском каждой функцииthat
Ты не устал?
И в функции стрелкиthis
Он указывает на внешний слой, полностью удаляя избыточный код выше! 💯
могу написать=>
, не пишиfunction
. Вместо использования стрелочных функций дляthis
указывают на внешний слой, аfunction
ключевые слова используются дляthis
Он будет использоваться только в том случае, если указывает на этот слой.
- Упрощенное написание
почувствуй это первым
mouseList.find(function(mouse) {
return mouse.name === '小绿鼠'
})
// 箭头函数写法
mouseList.find(mouse => mouse.name === '小绿鼠')
Нужно ли писать намного меньше, со сравнением способов написания
написание | function | (параметр) | => | { | автоматический возврат | тело функции | } |
---|---|---|---|---|---|---|---|
оригинальное письмо | function | (параметр) | { | тело функции | } | ||
Стрелка 1 | (параметр) | => | { | тело функции | } | ||
Стрелка 2 | (параметр) | => | // имеют | одна строка кода |
Функции стрелок потрясающие! Писатели могут меньше писать, а зрители меньше читать. См. конкретное использованиеДокументация, посмотрим вниз
цикл
посмотри это первымfor
петля, она длинная и широкая
for (var i = 0; i < mouseList.length; i++) {
if (mouseList[i].name == '小绿鼠') {
mouseList[i].cap.color = 'green'
}
}
Очевидно, переменная здесьi
бессмысленно, так как удалитьi
Шерстяная ткань? 🤔
Первый заключается в использованииES6
изfor..of
for (const mouse of mouseList) {
if (mouse.name == '小绿鼠') {
mouse.cap.color = 'green'
}
}
Но используйтеfor...of
, даже если вы хотите подписатьсяi
Дать тоже не может.Рекомендуется, в общем-то можно пользоваться.forEach
используется всякий раз, когдаArray.prototype.forEach()
mouseList.forEach((mouse) => {
if (mouse.name == '小绿鼠') {
mouse.cap.color = 'green'
}
})
проиллюстрировать:for...of
Может проходить через все развертыванияiterator
(итератор) данные, в то время какforEach
Просто метод на прототипе массива. Но если вы решили использоватьforEach
, пригодный для использованияспред оператор(...) для преобразования итерации в массив:[...iterableValue].forEach()
forEach
Это полезно, но не просто используйте этоforEach
До смерти так много полезных методов для массивов, и они более полные и более упакованные.Семантический, если вы не знакомы с методами массива, можете прочитать несколько разДокументация
Я знаю, что есть письменный метод, но я не могу вспомнить, как его использовать?
Прежде чем писать цикл, подумайте, чего вы хотите в итоге, а затем начинайте после того, как у вас появится четкая цель.
Цель | означает | возвращаемое значение |
---|---|---|
найти предмет | find |
элемент массива (не найденundefined ) |
найти индекс | findIndex |
number (Не найдено-1 ) |
найти несколько (фильтр) | filter |
array |
скопируй все и трансформируй | map |
array |
Некоторые? | some |
boolean |
Все они? | every |
boolean |
... | ... | ... |
Разрушение (разрушение)
Деструктурирование присваивания переменных (деструктурирование)
Существует много видов деструктуризации переменных, все они похожи, здесь представлен только наиболее часто используемый.деструктуризация объекта
пример
Предположим, мы хотим удалить несколько свойств мыши, не разрушая присваивание, как это
const whiteMouse = { id: 'm01', name: '小白鼠', type: '0' }
const id = whiteMouse.id
const name = whiteMouse.name
const type = whiteMouse.type
Присваивание с деструктурированием выглядит так
const whiteMouse = { id: 'm01', name: '小白鼠', type: '0' }
const { id, name, type } = whiteMouse
Преимущество очевидно, удаление большого количества избыточного кода.
Деструктурирование можно использовать во многих местах. Пока вы присваиваете атрибут объекта переменной, вы можете использовать деструктурирование. Ниже приведена расширенная версия примера с зеленой мышью.
const greenMouse = mouseList.find(mouse => mouse.name === '小绿鼠')
if (greenMouse) {
greenMouse.cap.color = 'green'
greenMouse.cap.size = 'big'
greenMouse.cap.brightness = 'high'
}
Обеспокоенные тем, что это слишком эвфемистично для маленькой зеленой мышки, мы увеличили размер шляпы 🎩 и сделали ее более ослепительной.
При встрече с таким свойством объектаиспользовать много разВ случае , лучше всего использовать переменную для его хранения, чтобы избежать многократного对象.属性.属性...
Написание делает код раздутым и влияет на чтение.
const greenMouse = mouseList.find(({ name }) => name === '小绿鼠')
if (greenMouse) {
const { cap } = greenMouse
cap.color = 'green'
cap.size = 'big'
cap.brightness = 'high'
}
Его легко понять и легко использовать, но если вы будете осторожны, вы обнаружите, что есть еще одно место, где также используется деконструкция, а именно.find()
Часть параметров функции обратного вызова.
Подобная запись может уменьшить пользовательскую переменнуюmouse
, он также не имеет отношения к теме и используется только один раз, когда он определен, что также считается своего рода избыточностью.
Объясните эту деконструкцию
(mouse) => mouse.name === '小绿鼠'
.find()
входящая функция обратного вызова(mouse) => mouse.name === '小绿鼠'
,
его первый параметрmouse
,ДаmouseList
элементы в , т.е.
{ id: 'm01', name: '小白鼠', type: '0' } // 第一次回调运行时`mouse`的值
{ id: 'm02', name: '小黑鼠', type: '4' } // 第二次回调运行时`mouse`的值
// ...
теперь, когдаmouse
это объект, нам просто нужно егоname
свойства, то({ name })
просто поставь
const mouse = { id: 'm01', name: '小白鼠', type: '0' }
изменился на
const { name } = { id: 'm01', name: '小白鼠', type: '0' }
Деструктурирование действительно распространено, когда интерфейс запроса возвращается, он часто пишется так
async function getData() {
const { code, msg, data } = await requestFn()
// ...
}
Так вот такое предложение, после запроса интерфейса поставить回调函数
а также.then()
Убери это, посмотри на этоasync + await
, разве это не ясно, разве это не читабельно?
наконец
Два дня на выходных я потратил на эту статью, надеюсь она будет полезна всем моим друзьям. Если в тексте есть ошибки, или есть предложения, укажите на них, спасибо 😘.