Ваш код JS мог бы быть более элегантным

JavaScript

Иногда интересно посмеяться над собой, болтая в группе: «Проект хх наконец-то стал неподдерживаемым после года непрерывных усилий». Лично для меня сопровождение — более сложная вещь, чем разработка, стандартизированность и элегантность кода предшественников напрямую повлияет на нашу эффективность работы и настроение.

Поэтому мы всегда должны обращать внимание на качество нашего кода, возможно, ваш код достаточно стандартизирован, но в какой-то мере недостаточно элегантен. В этой статье перечислены некоторые советы и предложения по тому, как сделать код JS более элегантным, я надеюсь, что это поможет вам.

майнкрафт больше, чем если бы еще

В случае логического суждения часто наша первая реакция состоит в том, чтобы использовать if else / switch для решения, потому что это синтаксис, который лучше всего соответствует нашему императивному логическому мышлению (не потому ли, что книга учит только этим двум).

Но когда есть много ситуаций, которые необходимо оценить в нашем сценарии логического суждения, использование if else / switch может решить нашу проблему, но это делает код излишним и не элегантным.

Например, соответствующий тип ученика оценивается по типу типа.

// if else
let getStudentType = (type) =>{
  if(type == 1){
    console.log('学神')
  } else if (type == 2){
    console.log('学霸')
  } else if (type == 3) {
    console.log('学渣')
  } else {
    console.log('学灰')
  }
}
// switch
let getStudentType = (type) => {
  switch (type) {
    case 1:
      console.log('学神')
      break
    case 2:
      console.log('学霸')
      break
    case 3:
      console.log('学渣')
      break
    default:
      console.log('学灰')
      break
  }
}

Как и выше, хотя логика кода может быть визуально выражена через синтаксис if else/switch, он кажется немного избыточным. На самом деле, для сценария логического суждения у нас может быть больше других способов его решения; на самом деле, ваш JS-код мог бы быть более элегантным.

Тернарный оператор

Если логическое суждение предназначено только дляназначатьоперации, то мы обычно можем использовать тернарный оператор для ее решения.

let getStudentType = (type) => {
  let studentType = type == 1 ?'学神'
    : type == 2 ? '学霸'
      : type == 3 ? '学渣' : '学灰';
  console.log(studentType)
}

Он выглядит более удобным?

Объект / объект карты

В основном все операции логического суждения могут быть решены с помощью объектов Object / Map.

// Object 对象
let getStudentType = (type) => {
  let obj = {
    1:'学神',
    2:'学霸',
    3:'学渣',
    0:'学灰'
  }
  let studentType = obj[type] || obj['0'];
  console.log(studentType);
}
// Map 对象
let getStudentType = (type) => {
  let map = new Map([
    [1, '学神'],
    [2, '学霸'],
    [3, '学渣'],
    [0, '学灰']
  ])
  let studentType = map.get(type) || map.get('0');
  console.log(studentType);
}

В сцене логического суждения мы все еще можем реализовать элегантный код с помощью объекта Object / Map.Конечно, упомянутые выше каштаны - это только сцена операции присваивания в логическом суждении, а в сцене логического суждения требуется выполнить больше операций , объекты Объект/Карта могут лучше отражать свои преимущества.

Давайте расширяемся над каштанами, после определения соответствующего типа по типу типа студентов каждый студент также будет запустить свои собственные соответствующие типы навыков.

Способ достижения этого через if else заключается в следующем

// if else
let studentAction = (type) =>{
  if(type == 1){
    console.log('学神')
    launchXueshenSkill();
  } else if (type == 2){
    console.log('学霸')
    launchXuebaSkill();
  } else if (type == 3) {
    console.log('学渣')
    launchXuezhaSkill();
  } else {
    console.log('学灰')
    launchXuehuiSkill();
  }
}

А через объект Object/Map можно реализовать более изящно

// Object 对象
let getStudentType = (type) => {
  let obj = {
    1: () => { console.log('学神'); launchXueshenSkill(); },
    2: () => { console.log('学霸'); launchXuebaSkill(); },
    3: () => { console.log('学渣'); launchXuezhaSkill(); },
    0: () => { console.log('学灰'); launchXuehuiSkill(); },
  }
  let studentSkill = obj[type] || obj['0'];
  studentSkill();
}
// Map 对象
let getStudentType = (type) => {
  let map = new Map([
    [1, () => { console.log('学神'); launchXueshenSkill(); }],
    [2, () => { console.log('学霸'); launchXuebaSkill(); }],
    [3, () => { console.log('学渣'); launchXuezhaSkill(); }],
    [0, () => { console.log('学灰'); launchXuehuiSkill(); }]
  ])
  let studentSkill = map.get(type) || map.get('0');
  studentSkill()
}

Объекты Object и Map могут решить все проблемы логического суждения, так в чем же между ними разница?

Объект Map — это синтаксис в ES6.Самая большая разница между ним и объектом Object заключается в том, что ключ объекта Object может быть только строкой, а ключ объекта Map может быть любым значением.

Поэтому, условно говоря, объекты Map более гибкие, чем объекты Object.В более сложных логических суждениях, когда наши ключи уже не соответствуют требованиям, использующим строки, мы можем использовать только объекты Map для достижения нашей цели.

true && xxx

true && xxx в основном применим к некоторым простым сценариям в if else. Определите, является ли значение истинным, и если оно истинно, выполните соответствующие операции xxx.

let isGoodStudent = true;
// if else
if (isGoodStudent){
  console.log('我是一个好学生')
}
// true && xxx 
isGoodStudent && (console.log('我是一个好学生'));

Три строки кода, наконец, сокращены до одной строки, что действительно элегантно!

false || variable

Сценарий использования false || xxx — это краткий способ записи тернарного оператора в некоторых сценариях. Определяет, существует ли переменная, и присваивает другую переменную (переменную), если она не существует (false).

let studentType1 = '学神'
let studentType2 = '学霸'
// 三目运算符
let goodStudent = studentType1 ? studentType1 : studentType2;
// false || xxx
let goodStudent = studentType1 || studentType2;

мой мир не только для

В случае логических циклов часто нашей первой реакцией является использование for / while для решения, потому что этот синтаксис также лучше всего соответствует нашему императивному логическому мышлению (не потому ли, что книга учит только этим двум).

Но, например, если else/переключатель, for/пока более интуитивен, но и менее элегантен.

let studentType = ['学神', '学霸', '学渣', '学灰'];
// for
for (let i = 0, len = studentType.length; i < len; i++) {
  console.log(studentType[i]);
}
// while
let i = 0;
while (i < studentType.length){
  console.log(studentType[i]);
  i++;
}

Точно так же для сценария логического цикла у нас также может быть больше других способов его решения.

Array.prototype.forEach

Сценарий использования метода forEach() в основном такой же, как и для / while (цикл forEach не может быть прерван досрочно), поскольку это сценарий логического цикла, можно использовать forEach().

studentType.forEach((v,i) => {
  console.log(v);
})

Array.prototype.map

Если методу map() нужно только получить элементы массива для выполнения некоторых операций цикла, его использование такое же, как и forEach().

studentType.map((v, i) => {
  console.log(v);
})

Метод map() возвращает новый массив, результат которого является результатом вызова предоставленной функции для каждого элемента в исходном массиве.

Например, добавьте строку +10086 к каждому элементу типа studentType и верните новый массив.

llet superStudentType = studentType.map((v, i) => `${v}+10086`)
console.log(superStudentType); // [ '学神+10086', '学霸+10086', '学渣+10086', '学灰+10086' ]

Поэтому, помимо замены цикла for/while, метод map() также предоставляет функцию работы с элементами исходного массива и возврата нового массива (это можно реализовать и с помощью цикла for/while, но требует нужно написать больше кода).

Точно так же методы, перечисленные ниже для массивов, могут быть реализованы через циклы for / while, но использование следующих инкапсулированных методов сделает логику нашего кода более ясной, а сам код более кратким и элегантным.

Array.prototype.filter

Метод filter() возвращает новый массив, содержащий все элементы теста, реализованного предоставленной функцией.

let studentTypeWithScore = [{
    type:'学神',
    score:100
  },{
    type: '学霸',
    score: 85
  },{
    type: '学渣',
    score: 65
  },{
    type: '学灰',
    score: 50
  }]
let goodStudentType = studentTypeWithScore.filter((v, i) => v.score > 80)
console.log(goodStudentType); // [ { type: '学神', score: 100 }, { type: '学霸', score: 85 } ]

Array.prototype.find

Метод Find() Возвращает значение первого элемента, удовлетворяющего тестовой функции, предоставленной в массиве, в противном случае возвращает неопределенное значение.

Поэтому, когда мы хотим получить только первый элемент массива, удовлетворяющий условиям, использование метода find() более эффективно и лаконично, чем использование метода filter(). Метод find() прекращает обход, когда получает первый элемент, удовлетворяющий условиям, в то время как методу filter() необходимо пройти все элементы массива, чтобы получить все элементы, удовлетворяющие условиям, и удалить первый элемент.

let oneGoodStudentType = studentTypeWithScore.find((v, i) => v.score > 80)
console.log(oneGoodStudentType); // { type: '学神', score: 100 }

Array.prototype.some

Метод some() используется для проверки того, соответствует ли какой-либо элемент массива заданному условию.

Точно так же, когда мы хотим только определить, есть ли в массиве элементы, соответствующие условию, использование метода some() более эффективно и лаконично, чем использование метода find(). Метод some() возвращает логическое значение, а метод find() возвращает значение первого элемента, соответствующего условию.

let hasGoodStudentType = studentTypeWithScore.some((v, i) => v.score > 80)
console.log(hasGoodStudentType); // true

Array.prototype.every

Метод Every() проверяет, все ли элементы массива проходят тест указанной функции.

let isAllGoodStudentType = studentTypeWithScore.every((v, i) => v.score > 80)
console.log(isAllGoodStudentType); // false
let isAllStudentType = studentTypeWithScore.every((v, i) => v.score > 40)
console.log(isAllStudentType); // true

Array.prototype.reduce

Метод reduce() применяет функцию к аккумулятору и каждому элементу массива (слева направо), сводя его к одному значению.

let sum = studentTypeWithScore.reduce((acc, curVal) => acc + curVal.score, 0); // 100 + 85 + 65 + 50
console.log(sum); // 300

Другие советы и рекомендации

  1. Используйте String.prototype.includes вместо String.prototype.indexOf, когда нужно просто определить, существует ли подстрока в строке;
  2. Используйте Array.prototype.includes вместо Array.prototype.indexOf, когда нужно просто определить, существует ли элемент в массиве;
  3. Максимально минимизировать вложенность блоков кода;
  4. По возможности используйте синтаксис ES6 и более новый;

Иногда элегантность кода основана на жертвовании читабельностью кода и производительностью.Вы не можете иметь и то, и другое.Конкретный метод реализации по-прежнему требует различных компромиссов в соответствии с реальной сценой.