【问题标题】:JavaScript reduce and destructuring questionJavaScript 减少和解构问题
【发布时间】:2020-07-20 21:21:29
【问题描述】:

我目前正在关注 James Moore 在 Udemy 上的 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 方法返回一个包含所有等级及其对应数量的对象,而不是每个等级的单独对象?

提前感谢您的任何建议。

【问题讨论】:

  • const a=0, b=0, c=0, d=0, f=0; 不会像解构那样将变量初始化为acc 的属性值。
  • 请注意,这不是最干净的代码。编写两个单独的函数会更好,例如counts(gradePoints.map(pointsToGrade))

标签: javascript arrays object destructuring reducers


【解决方案1】:

我的第一个问题是;为什么在这里使用解构而不是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);

这并没有回退到零只是为了清楚地了解正在发生的事情。可以使用the conditional operator ? : 完成后备值,如下所示:

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}
`)

另外,an idiomatic usage of the OR operator || 也可以产生一个后备值:

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结果。除非这是第一次调用它,否则它将使用提供给.reduceinitialValue
    • 注意 - previousResult 经常被命名为 prev 表示“以前的”或 acc 表示“累加器”。为了清楚起见,我选择了长格式,但您可以在代码中看到 acc - 这是此参数的惯用名称。
  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|
-------------------

同样适用于问题中的代码 - 每次回调只生成一个 single 对象,因此下次调用 acc 时将再次获得一个对象。

最后是using the object spread notation ... to clone and modify a value更新对象的方式。 {...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);

【讨论】:

    【解决方案2】:

    我的第一个问题是;为什么在这里使用解构而不是 常量 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。如果firstNamelastName 为空,那么我们必须获取默认名称。

    这是我们通常的做法:

    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};

    要知道为什么你需要知道 reduce 方法是如何工作的。来自 MDN 文档:

    reduce() 方法在 数组的每个元素,产生一个输出值

    所以每次使用accgrade 调用computer 方法并在最后返回一个值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-18
      • 2018-01-23
      • 1970-01-01
      • 2021-03-10
      相关资源
      最近更新 更多