JavaScript reduc 和解构问题



我目前正在学习James Moore的Functional programming for beginners with JavaScript on Udemy课程。我在理解一段代码的工作原理时遇到了一点麻烦:

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;?与原始技术相比,这似乎远没有那么冗长?

如果按照建议声明变量,则不会从对象中获取以前的值:

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

或者,OR 运算符||的惯用法也可以生成回退值:

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. 回调函数的上一个结果。除非这是第一次调用它,否则它将使用提供给.reduceinitialValue
    • 注意 -previousResult经常被命名为"先前"的prevacc的"累加器"。为了清楚起见,我选择了长形式,但正如您所看到的,代码中的那个是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|
-------------------

问题中的代码也是如此 - 每次回调只生成一个对象,所以下次调用它时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);

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

让我们看看如何在函数参数中使用解构。所以我们有一个返回用户fullNameuser对象。如果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方法时,最后返回单个值。

最新更新