---
# System prepended metadata

title: （穎旻試教版本）第二堂 - 進階陣列操作：掌握 filter 篩選技巧
tags: ["前端家教師資培訓班\_- 2024"]

---

# 第二堂 - 進階陣列操作：掌握 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
    **作業等級表**

    LV1：拿[CSS 現成模版](https://codepen.io/hexschool/pen/BaQveVm?editors=1010)套用，練習下方的套票列表用 JS 的 innerHTML 套用，並需運用 Code JS 面板裡面的 data 變數資訊，上方新增套票功能與下拉篩選地區功能可不做。


# 2. 介紹 filter 觀念
forEach vs 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 發送通知


// 2. 使用 filter 篩選大額訂單


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 協助解題

- 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 程式體驗營，臉書廣告數據為例

![image](https://hackmd.io/_uploads/HJ3CfIBhC.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/hexschool/pen/BaQveVm?editors=1010)

1. **實作：**
    - 示範使用陣列方法結合條件運算符來實現地區篩選。
        
        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>
        ```
        
        使用 filter：
        
        ```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)
        })
        ```
        
        **更好的程式碼：**
        - 運用 clean code 的概念，修改成更好的程式碼結構、命名規則等
        
        
        ```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