--- robots: noindex, nofollow tags: refactoring --- # Extract Function > 練習用的 [REPL](https://repl.it/@yaosiang/ExtractFunction)。 抽取時,若沒有任何變數會跑出 Scope,可以直接處理。 ```javascript= // Owing 欠款 function printOwing(invoice) { let outstanding = 0; console.log("***********************"); console.log("**** Customer Owes ****"); console.log("***********************"); // calculate outstanding(未清帳款) for (const o of invoice.orders) { outstanding += o.amount; } // record due date const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); // 別這樣做 // print details console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); console.log(`due: ${invoice.dueDate.toLocaleDateString()}`); } ``` ```javascript= function printOwing(invoice) { let outstanding = 0; printBanner(); // 先把畫 banner 的任務抽出來 // calculate outstanding for (const o of invoice.orders) { outstanding += o.amount; } // record due date const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); // print details console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); console.log(`due: ${invoice.dueDate.toLocaleDateString()}`); } function printBanner() { // 這裡不是 nested function console.log("***********************"); console.log("**** Customer Owes ****"); console.log("***********************"); } ``` 試著把註解內 `print details` 的部分都取出來。 ```javascript= function printOwing(invoice) { let outstanding = 0; printBanner(); // calculate outstanding for (const o of invoice.orders) { outstanding += o.amount; } // record due date const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); printDetails(); function printDetails() { // 把印出 details 的任務再抽出來,這邊是 nested function,可以直接取用所有變數 console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); console.log(`due: ${invoice.dueDate.toLocaleDateString()}`); } } function printBanner() { // 這裡不是 nested function console.log("***********************"); console.log("**** Customer Owes ****"); console.log("***********************"); } ``` 也可以直接傳遞變數 ```javascript= function printOwing(invoice) { let outstanding = 0; printBanner(); // calculate outstanding for (const o of invoice.orders) { outstanding += o.amount; } // record due date const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); printDetails(invoice, outstanding); } function printDetails(invoice, outstanding) { // 不是 nested-function,需要傳遞參數 console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); console.log(`due: ${invoice.dueDate.toLocaleDateString()}`); } ``` 有時候,需要處理一下變數才能抽取。 ```javascript= function printOwing(invoice) { let outstanding = 0; printBanner(); // calculate outstanding for (const o of invoice.orders) { outstanding += o.amount; } recordDueDate(invoice); printDetails(invoice, outstanding); } ``` ```javascript= function printOwing(invoice) { printBanner(); // calculate outstanding let outstanding = 0; // 換位子,方便抽取成 function for (const o of invoice.orders) { outstanding += o.amount; } recordDueDate(invoice); printDetails(invoice, outstanding); } ``` ```javascript= function printOwing(invoice) { printBanner(); // calculate outstanding let outstanding = 0; for (const o of invoice.orders) { outstanding += o.amount; } recordDueDate(invoice); printDetails(invoice, outstanding); } function calculateOutstanding(invoice) { // 經過 slide statement 後,可以整塊複製貼上 let outstanding = 0; for (const o of invoice.orders) { outstanding += o.amount; } return outstanding; } ``` ```javascript= function printOwing(invoice) { printBanner(); let outstanding = calculateOutstanding(invoice); // 把程式碼換成 function recordDueDate(invoice); printDetails(invoice, outstanding); } function calculateOutstanding(invoice) { let outstanding = 0; for (const o of invoice.orders) { outstanding += o.amount; } return outstanding; } ``` ```javascript= function printOwing(invoice) { printBanner(); const outstanding = calculateOutstanding(invoice); // 改成 const,避免被意外重新賦值 recordDueDate(invoice); printDetails(invoice, outstanding); } function calculateOutstanding(invoice) { let result = 0; // 命名成 result 是 Martin Fowler 的習慣 for (const o of invoice.orders) { result += o.amount; } return result; } ```