# 第二堂:進階陣列操作:掌握 filter 篩選技巧 ## 本堂課程重點 - forEach:**遍歷**陣列中的每一個元素 - filter:**篩選**陣列中符合條件的元素 # 課程大綱 1. forEach 練習 1. 1 個觀念 - 20min 2. 介紹 filter 觀念 1. 1 個觀念 - 25min 3. 試著用 forEach、Filter 協助解題 1. 1 個觀念- 25min 4. 題目複習 1. 1 個觀念 - 25min ## 1. forEach 練習 ```jsx let data = [ { "name": "肥宅心碎賞櫻3日", "area": "高雄", "price": 1400, "rate": 10 }, { "name": "貓空纜車雙程票", "area": "台北", "price": 240, "rate": 2 }, { "name": "台中谷關溫泉會1日", "area": "台中", "price": 1765, "rate": 7 } ]; ``` ### 問答 1. 用 forEach 計算所有套票的總價 2. 用 forEach 計算評價在 7 以上的套票 3. 高雄有幾筆資料 4. 撰寫[第五週作業 LV1](https://codepen.io/hexschool/pen/BaQveVm?editors=1010) ## 2. 介紹 filter 觀念 當然!這裡有一個 `forEach` 和 `filter` 的差異表格,你可以使用這個表格來清楚地展示它們之間的不同: | 差異點 | `forEach` | `filter` | | --- | --- | --- | | **用途** | **遍歷**陣列中的每一個元素 | **篩選**陣列中符合條件的元素 | | **回傳值** | **沒有回傳**值 (回傳 `undefined`) | **回傳**一個新的陣列 | | **是否改變原陣列** | 不會改變原陣列 | 不會改變原陣列 | | **用例** | 僅執行操作,不需要篩選或回傳新陣列 | 篩選出符合條件的元素並回傳新陣列 | ### 電商訂單情境 1. **發送通知**:向每位顧客發送 `console.log` 通知,確認訂單已經處理 2. **篩選大額訂單**:需要找出金額超過 $100 的訂單,看看誰是大戶 ```jsx // 訂單清單 const orders = [ { id: 1, amount: 50, customer: 'Alice' }, { id: 2, amount: 150, customer: 'Bob' }, { id: 3, amount: 200, customer: 'Charlie' }, { id: 4, amount: 80, customer: 'David' } ]; // 1. 使用 forEach 發送通知 orders.forEach(function(order) { console.log('通知顧客 ' + order.customer + ':訂單 ' + order.id + ' 已處理'); }); // 2. 使用 filter 篩選大額訂單 const highValueOrders = orders.filter(function(order) { return order.amount > 100; }); console.log('大額訂單清單:', highValueOrders); // filter 回傳一個新的陣列,其中包含符合條件的訂單 // 小題目,以下 orderConsole 變數的值是? // 1. undefined // 2. 全部 console 的總和 const orderConsole = orders.forEach(function(order) { console.log('通知顧客 ' + order.customer + ':訂單 ' + order.id + ' 已處理'); }); ``` ### 小技巧教學: debugger ```jsx const orders = [50, 150, 200, 80]; const highValueOrders = orders.filter(function(amount) { debugger; // 這行會在瀏覽器的開發者工具中暫停程式執行 return amount > 100; }); ``` 1. 遍歷陣列:從陣列的第一個元素開始,逐個檢查每個元素。 2. 應用條件函式:對於每個元素,會將該元素作為參數傳遞給指定的條件函式。這個條件函式**返回一個布林值**,表示是否將該元素包含在最終的篩選結果中。 3. 篩選元素:**如果條件函式返回`true`,則該元素將被保留在結果陣列中**;如果返回`false`,則該元素將被排除在外。 4. 回傳結果陣列:當所有元素都遍歷完畢後,**`filter()`**方法**返回一個新的陣列**,其中包含所有符合條件的元素,而原始陣列不受影響。 ## 3. 試著用 forEach、filter 協助解題 ## 電商廣告通路評估 | 廣告通路 | 廣告支出 (spend) | 廣告收入 (revenue) | 投資回報率 (ROAS) = revenue/spend | | --- | --- | --- | --- | | Google Ads | 10,000 | 35,000 | 3.5 | | Facebook Ads | 8,000 | 24,000 | 3.0 | | LinkedIn Ads | 5,000 | 12,000 | 2.4 | | Twitter Ads | 4,000 | 10,000 | 2.5 | | Instagram Ads | 6,000 | 15,000 | 2.5 | ### 表格解釋 - **廣告通路**:各種不同的廣告平台。 - **廣告支出 (spend)**:花出去的廣告費。 - **廣告收入 (revenue)**:透過廣告賺來的營業額。 - **投資回報率 (ROAS)**:收入與支出的比值,表示每花費一單位的廣告費所帶來的收益 ### 六角 2022 程式體驗營,臉書廣告數據為例 ![截圖 2024-08-23 下午6.22.13](https://hackmd.io/_uploads/H1pAhkUiC.png) ## roas 效益介紹 1. roas 在 1 以下:廣告效益差,可能會決定不投 2. roas 在 2~3:差強人意,列入評估。但在電商零售業或許會繼續投遞 3. roas 在 5~10 左右:效益不錯,六角學院廣告通常會盡可能在這個區間 ## 題目設計 ```jsx const marketingChannels = [ { name: 'Google Ads', spend: 10000, revenue: 35000, roas: 3.5 }, { name: 'Facebook Ads', spend: 8000, revenue: 24000, roas: 3.0 }, { name: 'LinkedIn Ads', spend: 5000, revenue: 12000, roas: 2.4 }, { name: 'Twitter Ads', spend: 4000, revenue: 10000, roas: 2.5 }, { name: 'Instagram Ads', spend: 6000, revenue: 15000, roas: 2.5 } ]; ``` ### 尋找高效行銷通路 1. 請設計一段程式碼來找出 ROAS(投資回報率)超過 3 的渠道,並將這些通路放入一個新陣列中 2. 請設計一段程式碼計算所有通路的總支出和總收入 ## 4. 旅遊套票練習 **實作:** - 示範使用陣列方法結合條件運算符來實現地區篩選([範例]( https://codepen.io/AliceChiang/pen/NWmgReN?editors=1111))。 ```html <select name="areaSelections" id="areaSelections"> <option value="全部">全部</option> <option value="台中">台中</option> <option value="台北">台北</option> <option value="高雄">高雄</option> </select> ``` 簡易寫法: ```jsx const data = [ { id: 0, area: "台中" }, { id: 1, area: "台中" }, { id: 2, area: "台北" }, { id: 3, area: "高雄" } ] const areaSelections = document.querySelector('#areaSelections'); let filterData = [] areaSelections.addEventListener('change', () => { if (areaSelections.value === '全部') { filterData = data; // 如果選擇的是「全部」,則返回所有資料 } else { filterData = data.filter((item) => areaSelections.value === item.area); }// console.log(filterData) }) ``` **更好的程式碼:** 討論地區篩選功能的最佳實踐,例如程式碼結構、命名規則等。 **進階寫法:** ```jsx const ticketList = [ { id: 0, area: "台中" }, { id: 1, area: "台中" }, { id: 2, area: "台北" }, { id: 3, area: "高雄" } ] const allAreas = '全部'; const areaSelections = document.querySelector('#areaSelections'); const filterTicketsByArea = (selectedArea) => { return ticketList.filter((ticket) => selectedArea === allAreas || selectedArea === ticket.area); }; areaSelections.addEventListener('change', () => { const selectedArea = areaSelections.value; const areaFilterData = filterTicketsByArea(selectedArea) // console.log(areaFilterData) }) ``` **變數命名:對應 Clean Code 原則「命名:使用具有意義且可閱讀的名稱」、「使用可解釋的變數」** - data → ****ticketList - filterData → areaFilterData - item **→** ticket **提取變數:對應 Clean Code 原則「使用可搜尋的名稱」** - const allAreas = '全部'; areaSelections.value === '全部' → areaSelections.value === allAreas - const selectedArea = areaSelection.value; **獨立函式:對應 Clean Code 原則「一個函式只做一件事情」** - filterTicketsByArea