我有兴趣了解此算法内部发生的情况。让我们考虑以下数据集:
const data = [
{
emp_code: "a001",
company_code: "company_a",
name: "abx",
details: [],
details_dtypes: []
},
{
emp_code: "b002",
company_code: "company_b",
name: "xbz ",
details: [],
details_dtypes: []
},
{
emp_code: "a002",
company_code: "company_a",
name: "xbz ",
details: [],
details_dtypes: []
},
{
emp_code: "b003",
company_code: "company_b",
name: "xbz ",
details: [],
details_dtypes: []
}
];
现在,如果我想将此数据压缩为object {}
,其中每个键是唯一的company_code
,并且其对应值是array []
的{{1}}公司,我可以做类似的事情:
emp_codes
在上面,我们显式地返回最终对象,这看起来很清楚。
现在,我最近发现您可以使用一些语法糖来缩短它,例如:
let result = data.reduce((r, c) => {
r[c.company_code] = [...(r[c.company_code] || []), c.emp_code];
return r;
}, {});
结果是相同的,但是我不确定这怎么可能。我对let result = data.reduce(
(r, c) =>
(r[c.company_code] = [...(r[c.company_code] || []), c.emp_code]) && r,
{}
);
的理解是,有一个内部循环遍历每个项目,并允许您应用某些逻辑来制定最终结果。
我看到他们正在使用reduce()
运算符。我的假设是,括号&&
之间的逻辑像传统的()
方法一样执行,当完成时,我们仅返回结果,因此返回reduce()
。
但是那件事似乎是错误的。内环还在发生吗?如果是这样,他们能够像这样隔离它,而不必在第一次迭代后简单执行条件,因此返回&& r
。他们是否为循环的每次迭代都返回r
?
这是一个沙箱,显示两种算法都有效:https://codesandbox.io/s/hooks-with-reduce-nested-data-goee1。非常感谢您的贡献:)
答案 0 :(得分:3)
对于&&
,如果涉及的所有表达式都是真实的,则它将求值为最终表达式的值-在&&
之后的表达式。因此,如果您有以下代码:
function foo() {
<some expression>;
return bar;
}
您也可以这样写
function foo() {
return <some expression> && bar;
}
或者,带有箭头函数的隐式返回:
const foo = () => <some expression> && bar;
等效于
const foo = () => {
<some expression>;
return bar;
};
是的,对于您的代码,在箭头函数的末尾带有&& r
,这意味着r
在每次迭代时都会隐式返回。
总而言之,这几乎与语法糖相反。如果您通过 minifier 运行代码,这是您经常会看到的事情,其目的是尽可能减少Javascript中的文本量。但是,精简代码通常很难阅读,正如您的问题所示,这也不例外。如果使用隐式return
要求逗号运算符或利用&&
来评估除布尔值以外的其他符号,则代码可能太容易混淆而难以理解,而显式{{1 }}可能是更好的选择。
您还可以考虑推送到累加器对象中的现有数组,从而避免创建许多不必要的中间数组,这些中间数组只会在以后传播:
return
那是我想要的代码。它更长一些,但是当每个语句/逻辑分支都位于自己的行时,它更容易阅读很多。
答案 1 :(得分:1)
让我们反汇编此行:
(r[c.company_code] = [...(r[c.company_code] || []), c.emp_code]) && r
JS always return assigned element中的赋值和逻辑AND运算符(&&
)遵循以下规则:
expr1 && expr2
如果expr1可以转换为true,则返回expr2
;否则,返回expr1
。
所以基本上和
相同if(r[c.company_code] = [...(r[c.company_code] || []), c.emp_code])
return r
并且由于JS中的数组([...(r[c.company_code] || []), c.emp_code]
)在解析为布尔值(顺便说一下,与对象,函数和符号相同)时会转换为true,因此它总是返回r。
答案 2 :(得分:1)
这里的问题很简洁。如果过多减少代码,则会降低可读性。这就是问题。让我们逆转过程并使您的代码更传统。
let result = data.reduce(
(r, c) => (r[c.company_code] = [...(r[c.company_code] || []), c.emp_code]) && r,
{}
);
第1、3和4行非常简单。棘手的部分是第2行。
(r, c) => (r[c.company_code] = [...(r[c.company_code] || []), c.emp_code]) && r,
这等效于:
function processData(accumulator, currentItem) {
if ( accumulator[currentItem.compony_code] === undefined ) {
accumulator[currentItem.compony_code] = [];
}
accumulator[currentItem.compony_code].push(currentItem.emp_code);
return accumulator;
}
现在开始假设()
,它是一种黑客,可以创建表达式并允许您执行非表达式(在这种情况下为赋值)任务。