迴圈切割術(Split Loop)
Split Loop 單從字面上的意思來看,就是把迴圈分開。
意思就是,當一個迴圈中,同時做了兩件以上不同的工作的時候,就應該把這些工作拆開來。
因為如果都濃縮在同一個迴圈的話,雖然可以一個迴圈就做完所有的工作,但會造成閱讀上的困難,如果要修改其中一個工作,要先分析完迴圈中所有工作在做的內容才能進行修改。
拆開迴圈的話,等於將不同的工作分別拆開來,對於之後的維護幫助很大。
在使用迴圈切割術的時候,常常會接著使用函式擷取術(Extract Function),可以更清楚了解每個迴圈的工作內容。
手術流程
- 複製迴圈
- 消除重複的工作內容
- 記得要測試功能是否正常運作
- 函式擷取術 (opt.)
範例
let youngest = people[0] ? people[0].age : Infinity;
let totalSalary = 0;
for (const p of people) {
if (p.age < youngest) youngest = p.age;
totalSalary += p.salary;
}
return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
範例中有一個迴圈,在做兩個不同的工作。一個是在計算最年輕多少歲數;一個是計算薪水加總。
根據上面的手術流程,我們首先複製迴圈
複製迴圈
let youngest = people[0] ? people[0].age : Infinity;
let totalSalary = 0;
for (const p of people) {
if (p.age < youngest) youngest = p.age;
totalSalary += p.salary;
}
for (const p of people) {
if (p.age < youngest) youngest = p.age;
totalSalary += p.salary;
}
return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
消除重複的工作內容
let youngest = people[0] ? people[0].age : Infinity;
let totalSalary = 0;
for (const p of people) {
//if (p.age < youngest) youngest = p.age;
totalSalary += p.salary;
}
for (const p of people) {
if (p.age < youngest) youngest = p.age;
//totalSalary += p.salary;
}
return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
記得做測試
到目前為止,迴圈切割術已經完成了,並且經測試功能正常,再來,可以考慮函式擷取術
了。
但在這之前,我們先使用陳述句滑動術(Slide Statements)讓程式碼更好閱讀,也能讓函式擷取術更順利執行。
陳述句滑動術
let totalSalary = 0;
for (const p of people) {
//if (p.age < youngest) youngest = p.age;
totalSalary += p.salary;
}
let youngest = people[0] ? people[0].age : Infinity;
for (const p of people) {
if (p.age < youngest) youngest = p.age;
//totalSalary += p.salary;
}
return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
函式擷取術
return `youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`;
function totalSalary() {
let totalSalary = 0;
for (const p of people) {
totalSalary += p.salary;
}
return totalSalary;
}
function youngestAge() {
let youngest = people[0] ? people[0].age : Infinity;
for (const p of people) {
if (p.age < youngest) youngest = p.age;
}
return youngest;
}
補充
作者說他很難抗拒用迴圈取代管線術 (Replace Loop with Pipeline)計算總薪資,以及用迭代演算法(Substitute Algorithm)計算最年輕年齡。
return `youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`;
function totalSalary() {
return people.reduce((tota, p) => total + p.salary, 0);
}
function youngestAge() {
return Math.min(...people.map(p => p.age));
}