JavaScript вопрос уменьшения и разрушения - PullRequest
1 голос
/ 08 апреля 2020

В настоящее время я слежу за функциональным программированием Джеймса Мура для начинающих с JavaScript курсом по Удеми. У меня возникли небольшие проблемы с пониманием того, как работает фрагмент кода:

const grades = [22, 77, 89, 90, 45, 77, 87, 92, 66, 44, 74, 81, 82, 81, 97];

const gradeCount = grades.reduce(computer, {});

function computer(acc, grade){
  const {a = 0, b = 0, c = 0, d = 0, f = 0} = acc;
  if (grade >= 90){
      return {...acc, a: a + 1};
  } else if (grade >= 80){
      return {...acc, b: b +1};
  } else if (grade >= 70){
      return {...acc, c: c + 1};
  }else if (grade >= 60){
      return {...acc, d: d + 1};
  } else { 
      return {...acc, f: f + 1};
  }
}

console.log(gradeCount);

  1. Мой первый вопрос: почему здесь используется деструктуризация, а не const a=0, b=0, c=0, d=0, f=0;? Это кажется гораздо менее многословным по сравнению с оригинальной техникой?

  2. Во-вторых, почему метод Reduce возвращает один объект, содержащий все оценки с соответствующими количествами, а не отдельный объект? за каждый класс?

Заранее благодарим за любые советы.

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Мой первый вопрос: почему здесь используется деструктуризация, а не const a=0, b=0, c=0, d=0, f=0;? Это кажется гораздо менее многословным по сравнению с оригинальной техникой?

Если вы объявите переменные так, как вы предлагаете, вы не получите предыдущие значения из объекта:

function original(obj) {
  const { a=0, b=0, c=0, d=0, f=0 } = obj;
  console.log(`const { a=0, b=0, c=0, d=0, f=0 } = obj;
a = ${a}
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}

function proposed(obj) {
  const a=0, b=0, c=0, d=0, f=0;
  
  console.log(`const a=0, b=0, c=0, d=0, f=0;
a = ${a}
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}

const obj = { a: 1, b: 2, d: 4};

original(obj);
proposed(obj);

Уничтожение заберет свойство a у объекта на правой стороне = и присвоит ноль только в том случае, если он его не найдет. Итак, это похоже на непосредственное получение свойств:

function explicit(obj) {
  const a = obj.a,
        b = obj.b, 
        c = obj.c, 
        d = obj.d, 
        f = obj.f;
  console.log(`const a = obj.a, b = obj.b, c = obj.c, d = obj.d, f = obj.f;
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}

const obj = { a: 1, b: 2, d: 4};

explicit(obj);

Это не имеет отступления к нулю только для ясности того, что происходит. Резервное значение можно сделать с помощью условного оператора ? :, который будет выглядеть следующим образом:

const obj = {b: 2};

const a = obj.a ? obj.a : 0;
const b = obj.b ? obj.b : 0;

console.log(`Using the conditional operator "? :"
a = ${a}
b = ${b}
`)

В качестве альтернативы, идиоматический c использует оператор ИЛИ ||, который также может давать запасное значение:

const obj = {b: 2};

const a = obj.a || 0;
const b = obj.b || 0;

console.log(`Using the OR operator "||"
a = ${a}
b = ${b}
`)

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

Таким образом, с учетом этого, деструктуризация на намного менее многословна, чем обычный способ:

const a = obj.a || 0,
      b = obj.b || 0, 
      c = obj.c || 0, 
      d = obj.d || 0, 
      f = obj.f || 0;

//compared with

const { a=0, b=0, c=0, d=0, f=0 } = obj;

Во-вторых, почему метод Reduce возвращает один объект, содержащий все оценки с соответствующими количествами, а не отдельный объект для каждой оценки?

Ну, это как работает Array#reduce. Я собираюсь немного упростить вещи и пропустить нерелевантные детали для краткости - не стесняйтесь читать документацию по MDN, поскольку она намного более тщательна, чем я буду здесь.

Форма reduce такая:

<array>.reduce(callback, initialValue)

Где вы предоставляете ему функцию обратного вызова, которая будет вызываться один раз для каждого элемента в массиве с двумя параметрами:

function callback(previousResult, currentItem){}
  1. previous результат функции обратного вызова. Если это не первый раз, когда он вызывается, в этом случае он будет использовать initialValue, предоставленный .reduce.
    • note - previousResult очень часто называют prev для "предыдущего" или acc для "аккумулятора". Для ясности я выбрал длинную форму, но, как вы можете видеть, в вашем коде acc - это идиоматическое c имя для этого параметра.
  2. Текущий элемент прооперирован Элементы будут последовательно посещаться последовательно.

Быстрая иллюстрация с использованием простого reduce для суммирования всех элементов в массиве:

callback = (acc, currentNumber) => acc + currentNumber;
initialValue = 0;
[1, 2, 3].reduce(callback, initialValue);

затем шаги .reduce будет показано здесь:

                    [3,   5,   7]
                     ^    ^    ^
----------------------    |    |
acc =           0 |       |    |
currentNumber = 3 |       |    |
result =        3 |       |    |
-------------------       |    |
                          |    |
---------------------------    |
acc =           3 |            |
currentNumber = 5 |            |
result =        8 |            |
-------------------            |
                               |
--------------------------------
acc =           8 |
currentNumber = 7 |
result =        15|
-------------------

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

Наконец, способ обновления объекта на с использованием нотации распространения объекта ... для клонирования и изменения значения . {...acc} создаст новый объект, который имеет те же значения, что и предыдущий, а {...acc, a: a + 1} клонирует его и изменит свойство a на значение переменной a плюс 1. Если раньше свойства a не было, оно будет добавлено и, поскольку переменная a будет равна нулю, вы получите { a: 1 }.

const initial = { a: 5};

const obj1 = {...initial, a: 6};
console.log("obj1", obj1);

const obj2 = {...obj1, b: 1};
console.log("obj2", obj2);

const obj3 = {...obj2, b: 2};
console.log("obj3", obj3);
1 голос
/ 08 апреля 2020

Мой первый вопрос: почему здесь используется деструктуризация, а не const a = 0, b = 0, c = 0, d = 0, f = 0 ;? Это выглядит гораздо менее многословно по сравнению с оригинальной техникой?

Так что обычный способ присваивания переменных выглядит примерно так:

const obj = {
  a: 'A',
  b: 'B',
  c: 'C',
  d: 'D',
  e: 'E'
}

let a = obj.a || 0,
  b = obj.b || 0,
  c = obj.c || 0,
  d = obj.d || 0,
  e = obj.e || 0;

Вы видели, сколько это кода ? Давайте добьемся того же, используя деструктуризацию.

let {a = 0, b = 0, c = 0, d = 0, e = 0} = obj;

Это намного лучше и делает то же самое. Он определяет переменные из a to e и устанавливает default value to 0.

Если вам необходимо получить вложенные значения от объекта, то destructuring делает это намного проще.

const user = {
  name: {
    firstName: 'John',
    lastName: 'Doe'
  },
  age: '26'
}

let {name: {firstName, lastName}, age} = user;

Посмотрим, как мы можем использовать деструктуризацию в параметрах функции. Итак, у нас есть user объект, который возвращает fullName пользователя. Если firstName или lastName пусто, то мы должны получить имя по умолчанию.

Вот как мы обычно это делаем:

function getUserFullName(user) {
  let firstName = user.firstName || 'Jane';
  let lastName = user.lastName || 'Doe';

  return firstName + ' ' + lastName;
}


const user = {
  name: {
    firstName: 'John',
    lastName: 'Doe'
  },
  age: '26'
}

getUserFullName(user);

То же самое, используя деструктуризацию, можно сделать следующим образом :

function getUserFullName({name: {firstName = 'Jane', lastName = 'Doe'}} = user) {
  return `${firstName} ${lastName}`;
}

const user = {
  name: {
    firstName: 'John',
    lastName: 'Doe'
  },
  age: '26'
}

getUserFullName(user);

Поначалу это может сбить с толку, но вы поймете, насколько это удобно, когда начнете его использовать.

Во-вторых, почему метод Reduce возвращает один объект, содержащий все оценки с соответствующими им количествами, а не отдельный объект для каждой оценки?

Это потому, что метод computer возвращает объект, содержащий все оценки.

return {...acc, a: a + 1};

Чтобы понять, почему вам нужно знать, как работает метод сокращения. Из документов MDN:

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

Поэтому каждый раз, когда метод computer вызывается с acc и grade, он возвращает одно значение в конце.

...