---
# System prepended metadata

title: (Chunglin) Object-oriented programming
tags: [AppWorks School]

---

###### tags: `AppWorks School`

# (Chunglin) Object-oriented programming 

## 跟著神奇寶貝學OOP！![](https://i.imgur.com/ril0V3z.png)


* 任務
* OOP 四大理論
    * 抽象化 Abstraction 
    * 繼承Inheritance
    * 多型 PolyMorphism
    * 封裝 Encapsulation



---

## 任務

你被派到銀河隊調查組，
被穿越時空的大木博士要求用 JS 寫出你的第一隻神奇寶貝

### 任務一、產生一個物件
你選擇了小火龍，一開始你這樣寫
```javascript=
let pokemon1name = "小火龍";
let pokemon1HP = 50;
let pokemon1STR = 30;
function attack(STR) {
  console.log(`attack in STR ${STR}`);
}
```

後來聽了博士助手子華建議，你決定用個object包裝
```javascript=
const pokemon1 = {
  name: "小火龍",
  HP: 50,
  STR: 30,
  attack() {
    console.log("attack in STR", this.STR);
  },
};

console.log(pokemon1);
// ▶{name: '小火龍', HP: 50, STR: 30, attack: ƒ}
console.log(pokemon1.name); //小火龍
pokemon1.attack; 
// ƒ attack() {
//    console.log("attack in STR", this.STR);
//  }
pokemon1.attack();
// attack in STR 30
```
### 任務二、產生多個物件

大木博士心血來潮，要你再創兩隻神奇寶貝
ctrl+c、ctrl+v
```javascript=
const pokemon2 = {
  name: "傑尼龜",
  HP: 49,
  STR: 29,
  attack() {
    console.log("attack in STR", this.STR);
  },
};

const pokemon3 = {
  name: "妙蛙種子",
  HP: 51,
  STR: 31,
  attack() {
    console.log("attack in STR", this.STR);
  },
};
```
![](https://i.imgur.com/gzdKLv4.png)

你發現每個神奇寶貝都有 `名字`、`HP`、`STR`、`攻擊` 四個東西
那不然把它寫成一個通用的 **設計圖** 好了

```javascript=
//class 類別 字首要大寫 
class Pokemon {
  constructor(name, hp, str) {
    this.name = name;
    this.HP = hp;
    this.STR = str;
  }
  attack() {
    console.log("attack in STR", this.STR);
  }
}

console.log(Pokemon);
// class Pokemon {...}
```
我們只是完成設計圖，沒有依照設計圖把神奇寶貝創出來

```javascript=
//實體化 Instance 
const 小火龍 = new Pokemon("小火龍", 50, 30);
const 傑尼龜 = new Pokemon("傑尼龜", 49, 29);
const 妙蛙種子 = new Pokemon("妙蛙種子", 51, 31);

console.log(傑尼龜);
// ▶Pokemon{name: '傑尼龜', HP: 49, STR: 29}
```
這個時候你就創好三隻活生生的神奇寶貝了
![](https://i.imgur.com/VQ4wQs0.png)

### 任務三、統整類別
子華提醒你，火系要會生火，而且應該有火屬性！
應該為火系創一個類別
可是每個火系都是神奇寶貝，應該有共用的地方
```javascript=
//繼承
class FirePokemon extends Pokemon {
  constructor(name, hp, str, fireproperty) {
    // 用super呼叫父層 Pokemon class
    super(name, hp, str);
    this.fire = fireproperty;
  }
  flame() {
    console.log("I Created some fire");
  }
}

let 小火龍 = new FirePokemon("小火龍", 50, 30, 40);
console.log(小火龍);  
// ▶FirePokemon{name: '小火龍', HP: 50, STR: 30, fire: 40}
小火龍.flame();
// I Created some fire
```
### 任務四、共同方法、不同內容
子華突然想到，神奇寶貝都會攻擊，可是各個屬性攻擊不同
火系神奇寶貝子攻擊時會噴火、水系的會噴水、草系的...

```javascript=
// 多型
class Pokemon {
  constructor(name, hp, str) {
    this.name = name;
    this.HP = hp;
    this.STR = str;
  }
  attack() {
    console.log("attack in STR", this.STR);
  }
}

//火系會噴火
class FirePokemon extends Pokemon {
  attack() {
    console.log("Fire attack in STR", this.STR);
  }
}

//水系會噴水
class WaterPokemon extends Pokemon {
  attack() {
    console.log("Water attack in STR", this.STR);
  }
}

//草系會...
class WeedPokemon extends Pokemon {
  attack() {
    console.log("Weed attack in STR", this.STR);
  }
}

let 小火龍 = new FirePokemon("小火龍", 50, 30);
let 傑尼龜 = new WaterPokemon("傑尼龜", 49, 29);
let 妙蛙種子 = new WeedPokemon("妙蛙種子", 51, 31);
小火龍.attack(); // Fire attack in STR 30
傑尼龜.attack(); // Water attack in STR 29
妙蛙種子.attack(); // Weed attack in STR 31
```

### 緊急任務、資料被竄改了！？

火箭隊趁子華去開會，潛入研究室偷改小火龍的數值
```javascript=
小火龍.HP = -1000;

console.log(小火龍);
// ▶FirePokemon {name: '小火龍', HP: -1000, STR: 30}
// 被竄改成功！？
```

你趕緊向組員道歉，一行一行看code決定用這樣的方式挽救
```javascript=
// #封裝
class PokemonNew {
  #name;
  #HP;
  #STR;

  constructor(name, hp, str) {
    this.#name = name;
    this.#HP = hp;
    this.#STR = str;
  }
  attack() {
    console.log("attack in STR", this.#STR);
  }
}

const 噴火龍 = new PokemonNew("噴火龍", 170, 100);
console.log(噴火龍);
// ▶PokemonNew {#name: '噴火龍', #HP: 170, #STR: 100}

噴火龍.attack();
// attack in STR 100
```
火箭隊又出沒，但他們這次發現改不動，你在旁邊滑ptt呵呵笑
```javascript=
// 封裝
噴火龍.STR = -200;
噴火龍.attack();
// attack in STR 100

噴火龍.#STR = -300;
// ✖ Uncaught SyntaxError: Private field '#STR' must be declared in an enclosing class

噴火龍.attack();
// attack in STR 100
```

![](https://i.imgur.com/gdHI12P.png)




---

## RECAP
### 屬性與方法

**任務一、產生一隻小火龍**
物件內通常會包含 `屬性Property`、`方法 Method`
屬性Property：該物件的資訊。
方法 Method：定義該物件的功能。
![](https://i.imgur.com/dyOVx66.png)

---

### 抽象化 Abstraction 
**任務二、產生御三家**
既有物件拆成class
![](https://i.imgur.com/u0Gzqjp.png)

### 實體化 Instance 
依照class 實際產生物件
![](https://i.imgur.com/f8rnEwm.png)

#### new 做了什麼？
1. 產生一個新的 obj
2. 把this 指到新的obj
3. 呼叫constructor

Ｏ
減少重複程式碼
易修改

---

### 繼承Inheritance
**任務三、創造火系類別**
重複使用相同程式碼，減少浪費重複工作時間
![](https://i.imgur.com/3Yw1MQG.png)
#### super
呼叫父層class的方法

---
### 多型 PolyMorphism
**任務四、各屬性不同的攻擊方式**
* #### 函式過載 Overloading (JS原則無)
* #### 函式覆寫 Overriding
先繼承、修改當中函式，爸媽和孩子的方法可產生不同結果
每個方法在不同class上會有不同結果

![](https://i.imgur.com/WWfFeQI.png)
```javascript=
let 小火龍 = new FirePokemon("小火龍", 50, 30);
小火龍.attack(); // Fire attack in STR 30
```
！ 方法名稱要相同

Ｏ
不會動到既有程式
好維護

---

### 封裝 Encapsulation
**緊急任務、避免資料遭更動**
保護資訊、不被輕易修改
#ES2019才支援，包含 public,protected,private

![](https://i.imgur.com/ca7DQJ2.png)
```javascript=
// 封裝
噴火龍.STR = -200;
console.log(噴火龍.attack());
// attack in STR 100

噴火龍.#STR = -300;
// ✖ Uncaught SyntaxError: Private field '#STR' must be declared in an enclosing class

噴火龍.attack();
// attack in STR 100
```


---


## OOP 是什麼？

![](https://i.imgur.com/56eBdA0.png)

#### OOP Object-oriented programming 物件導向
#### POP procedure-oriented programming 程序導向
一條一條寫程式，依照排序讓code執行


如果不用物件導向
![](https://i.imgur.com/1mrJMRY.png)
物件導向
![](https://i.imgur.com/QECGOn3.png)

#### 物件導向的寫法：
1. 定義參與這件事的物品　(aka 「物件」)
1. 定義物品所需的數量及行為　(aka 「屬性」 & 「方法」)
1. 用 1+2 描述事情發生(in 「主程式」)



#### 好處：
1. 便於程式碼「重用」
1. 把程式細節隱藏在物件內，
1. 讓主程式變短，
1. 簡化主程式邏輯
1. 多人開發方便
2. 方便製作同類物件
3. 提高開發與維護效率
⇔ 須了解內容 v.s. 只需知道方法

---

## 名詞複習

**OOP**　：　物件導向，以物件為核心，減少重工、提高開發維護效率的概念

**Object 物件**
* property 屬性　：　物件資訊
* method 方法　：　物件功能

**class 類別**　：　設計圖，分門別類

**Instance 實體化** ： class → object 
**Abstraction 抽象化** ： object → class 

**Inheritance 繼承**　：　重複使用相同程式碼，減少浪費重複工作時間
**PolyMorphism 多型**　：　一個子類繼承多個父類。相同名稱處理不同功能
**Encapsulation 封裝**　：　將屬性、方法、建構式封入類別，避免外部干擾跟誤用


## Reference
[MDN - new operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new)
[React - DOM界的彼方 Day 10: ES6篇 - Class(類別)](https://ithelp.ithome.com.tw/articles/10185583)
[從不懂，到玩上手的Python語言 DAY26-物件導向設計](https://ithelp.ithome.com.tw/articles/10227231)
[PTT - 物件導向的好處是....(JAVA)](https://www.ptt.cc/bbs/java/M.1292317058.A.8A3.html?fbclid=IwAR15OTTRYLHtxFUUyNbQs9h-L_WSIME1R1dT0O4xEDilahg9BPj07QZxLFw)
[初心者向けに徹底解説！オブジェクト指向とは？](https://eng-entrance.com/what-oop)
[オブジェクト指向の「カプセル化」とはなにか？超わかりやすく解説します！](https://webpia.jp/encapsulation/)

-------------------------------------------------
# (Dragon) Object-oriented programming (實作篇)    

## Javascript中的物件有哪些?
* 在 JavaScript 裡面，從諸如字串與陣列的核心功能、到以 JavaScript 建構的瀏覽器 API，**大部分的東西都可算是「物件 (Object)」**(Array, function...)

> **非物件型別(原始型別Primitive type)：**
> - Number
> - String
> - Boolean
> - null
> - undefined
> - bigInt


包含browser內的document, localstorage都是物件

![](https://i.imgur.com/cX9vaL4.png)

![](https://i.imgur.com/nWHxAu0.png)
-------------------------------------------------

## 如何自己創建一個物件

#### 在沒有class以前(function版本)
```javascript=
function Car(color, model) {
    this.color = color;
    this.model = model;
}

const modelY = new Car('white', 'Y');
console.log(modelY); // Car { color: 'red', model: 'Y' }
```
**在ES6後 有了class跟constructor**

#### class的版本
```javascript=
class Car {
    constructor(color, model) {
        this.color = color;
        this.model = model;
    }
}

const modelY = new Car('red', 'Y');
console.log(modelY); // Car { color: 'red', model: 'Y' }
```
這樣我們就創建好一個可重複使用且帶有**Property**的物件了

### 那如果我們要給物件加上Method呢?

#### class 版本
```javascript=
class Car {
    constructor(color, model) {
        this.color = color;
        this.model = model;
    }
    
    speak() {
        console.log(`I am a ${this.color}'s model ${this.model}`);
    }
}

const modelY = new Car('red', 'Y');
modelY.speak(); // I am a red's model Y
```

#### function 版本
透過`prototype`
```javascript=
function Car(color, model) {
    this.color = color;
    this.model = model;
}

Car.prototype.speak = function () {
    console.log(`I am a ${this.color}'s model ${this.model}`);
};

const modelY = new Car('red', 'Y');
modelY.speak(); // I am a red's model Y
```

**可以發現到class可以做到的事情，用function也做的到**

另外你可能也會想到，**function的版本其實可以寫得簡單一點**
不需要用到`prototype`
```javascript=
function Car(color, model) {
    this.color = color;
    this.model = model;
    this.speak = function () {
        console.log(`I am a ${this.color}'s model ${this.model}`);
    };
}

const modelY = new Car('red', 'Y');
modelY.speak(); // I am a red's model Y

const modelX = new Car('white', 'X');
console.log(modelY.speak === modelX.speak); // false
```
是可以達到一樣的功能，但就會造成每次都會產生一個**新的`speak` function**，會造成記憶體的浪費
> 類似於我們在寫React function component時，function內沒有被hook管理的變數、funcion、物件，會被重新宣告

**用prototype寫可以避免這個問題**，可以想像成function裡面寫的東西是每次被物件化時，會被執行的程式碼`等同於class內的constructor`，用prototype產生的method則是被呼叫時才會執行
```javascript=
function Car(color, model) {
    this.color = color;
    this.model = model;
}

Car.prototype.speak = function () {
    console.log(`I am ${this.color}'s model ${this.model}`);
};

const modelY = new Car('red', 'Y');
const modelX = new Car('white', 'X');
console.log(modelY.speak === modelX.speak); // true
```


## 那為什麼要有class
在ES6中的`class`(類別)語法，並不是真的是以類別為基礎`class-based`的物件導向，在骨子裡仍然是以原型為基礎`prototype-based`的物件導向，它只是個**語法糖`syntactical sugar`**。加入Class(類別)語法的目的，並不是要建立另一套物件導向的繼承模型，而是為了
* **提供更簡潔的語法來作物件建立與繼承**
* 讓已經熟悉以類別為基礎的物件導向程式語言的開發者使用，以此提供另一種在物件導向語法上的選擇。
> 語法糖：讓程式更加簡潔，有更高的可讀性

### 物件的繼承 (inheritance )

#### function版本
```javascript=
function Car(color, model) {
    this.color = color;
    this.model = model;
}

Car.prototype.speak = function () {
    console.log(`I am ${this.color}'s model ${this.model}`);
};

function NewCar(color, model) {
    Car.call(this, color, model);
}

NewCar.prototype.speak = function () {
    console.log(`I am a NEW ${this.color}'s model ${this.model}`);
};

const modelY = new NewCar('red', 'Y');
modelY.speak() // I am a NEW red's model Y
```
#### class版本
```javascript=
class Car {
    constructor(color, model) {
        this.color = color;
        this.model = model;
    }
    
    speak() {
        console.log(`I am ${this.color}'s model ${this.model}`);
    }
}

class NewCar extends Car {
    speak() {
        console.log(`I am a NEW ${this.color}'s model ${this.model}`);
    }
}

const modelY = new NewCar('red', 'Y');
modelY.speak(); // I am a NEW red's model Y
```
* 這邊會發現如果用`function`去寫，雖然可以達到一樣的功能，但就寫的比較麻煩
> 可以注意到我們用新的`class`取代被繼承的`class`的`speak method`，這牽扯到了`javascript`的原型鏈 `prototype chain`，簡單來說，一個物件本身如果本身有這個method，就會被執行，如果沒有的話，他就會往上層(被繼承的物件的`__proto__`)去找，如果有，就會執行，如果都沒有，就會是`undefined`

## 讓我們繼續學習class的語法

### 如果我們要繼承class並且增加constructor內容該怎麼做?
很簡單，只要在`constructor`的內容第一行打上`super()`，並且裡面帶上原`class consturctor`所需的參數即可
```javascript=
class Car {
    constructor(color, model) {
        this.color = color;
        this.model = model;
    }
    speak() {
        console.log(`I am ${this.color}'s model ${this.model}`);
    }
}

class NewCar extends Car {
    constructor(color, model, year) {
        super(color, model);
        this.year = year;
    }
    speak() {
        console.log(
            `I am a ${this.color}'s model ${this.model} car from future ${this.year}`
        );
    }
}

const modelY = new NewCar('black', 'Z', 2025);
modelY.speak(); // I am a black's model Z car from future 2025
```
* 如果為繼承的`class`要創建`constructor`，一定要在寫上第一個`this`之前加上`super()`
* `super()`的概念可以理解成：將原本的`class`內容先寫一遍
* 到這邊以前如果是用`function`搭配`prototype`產生出來的`method`或是`class`的寫法，又稱作`Prototype method`原型方法

-------------------------------------------------
### `class`中的 `static method` 靜態方法
* 如果我們今天創建一個紀錄位置的`class`，然後想要計算兩者之間的距離，可以怎麼做?

#### 如果你不知道`static`你可能只能這樣做
```javascript=
class Position {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

const p1 = new Position(0, 0);
const p2 = new Position(1, 1);

const distanceX = p1.x - p2.x;
const distanceY = p1.y - p2.y;

const distance = Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
```
#### `static`的寫法
```javascript=
class Position {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(p1, p2) {
        const distanceX = p1.x - p2.x;
        const distanceY = p1.y - p2.y;
        return Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
    }
}

const p1 = new Position(0, 0);
const p2 = new Position(1, 1);

const distance = Position.distance(p1, p2); // 1.414...

const distance2 = p1.distance(p1, p2); // TypeError: p1.distance is not a function
```
* `static`就是一個`class`的`method`，可以幫把當作一個`function`來使用，但只存在於`class`中，無法被物件使用，白話文說，就是**沒辦法透過被new的物件去呼叫他**
* 這邊又突顯出OOP的一個好處，就是不需要了解`class`內部`function`如何撰寫的，只要執行就好

-------------------------------------------------
### Getter / Setter

* 顧名思義，適用來**拿變數**跟**設定變數**的，直接看程式碼

#### `Getter`用來拿物件的`property`

```javascript=
class Car {
    constructor(color, model) {
        this._color = color;
        this.model = model;
    }
    
    get color() {
        return this._color;
    }
}

const modelY = new Car('white', 'Y');
console.log(modelY.color); // white
console.log(modelY._color); // white

modelY.color = 'black'; // 無法更改
console.log(modelY.color); // white

modelY._color = 'black';
console.log(modelY.color); // black
```
* 這邊可以看到把原本的`this.color`改成`this._color`是想要避免被外部直接更改，但如果知道變數的命名，還是可以直接修改的

#### `Setter` 用來設定物件的`property`

```javascript=
class Car {
    constructor(color, model) {
        this._color = color;
        this.model = model;
    }
    get color() {
        return this._color;
    }
    set color(color) {
        if (color === 'black' || color === 'white') {
            this._color = color;
        }
    }
}

const modelY = new Car('white', 'Y');
console.log(modelY.color); // white

modelY.color = 'black';
console.log(modelY.color); // black

modelY.color = 'blue';
console.log(modelY.color); // black

modelY._color = 'blue';
console.log(modelY.color); // blue
```
* `Setter`可以用來當作一個判斷式、如果符合才更改變數


### Getter / Setter的主要運用時機
* 用**同一個`method`名稱去拿取或更改`Object`的`Property`**，同時避免被直接存取
* 做一些邏輯處理 (`if`) 或資料處理 (數據轉換)
> class內的參數還是有方法可以避免被直接修改的，詳情可以搜尋`public/private class fields`


## OOP實際可以如何運用?
以Stylisy product page舉例，我們一般的寫法可能會像是這樣
由一個主要的function`productDetail`去呼叫其他function

```javascript=
function getProductData(url) {}
function arrangeInStockData(variants) {}
function renderProductDetail(productData, container) {}
function renderProductDescription(productData, container) {}
function checkAllStatus(inStock) {}
function bindSelectionEvent(inStock) {}
function bindAddToCartBtn(inStock, productData) {}

function productDetail(url) {
    const container = document.querySelector('.product');
    const productData = getProductData(url);
    const inStockData = arrangeInStockData(productData.variants);
    renderProductDetail(productData, container);
    renderProductDescription(productData, container);
    checkAllStatus(inStock);
    bindSelectionEvent(inStock);
    bindAddToCartBtn(inStock, productData);
}
```

可以看到很多同樣的參數被傳遞來傳遞去的，可能會衍伸出以下問題
- **漏寫參數**，導致某個function無法運作
- 當別人想沿用你的Code，複製過去的時候，不小心**漏掉某個function**

### 用Class來改善這個問題

```javascript=
class ProductDetail {
    constructor(url) {
        this.url = url;
        this.container = document.querySelector('.product');
        this.productData = this.getProductData();
        this.inStockData = this.arrangeInStockData();
        this.renderProductDetail();
        this.renderProductDescription();
        this.checkAllStatus();
        this.bindSelectionEvent();
        this.bindAddToCartBtn();
    }
    getProductData(){}
    arrangeInStockData(){}
    renderProductDetail(){}
    renderProductDescription(){}
    checkAllStatus(){}
    bindSelectionEvent(){}
    bindAddToCartBtn(){}
}
```
這樣一來，當別人要複製你的code，僅需要整包class複製
參數也不需要一直重複宣告、傳遞
同時可以把主要架構放在constructor，較容易閱讀

### 小結
- `javascript`中，大部分的東西都是物件
- `class`是一個語法糖，單純用function也可以寫出一樣的程式
- 物件可以繼承，可以免去寫出重複的程式碼，同時可以複寫掉舊有的method
- `static`僅限於class使用，被物件化`new XXX()`的無法使用
- Setter / Getter 主要用於保護內部property被直接修改，以及在存取數值時可以動些手腳
- 將複雜且相互依賴高的function合起來寫成一個class，可以避免參數重複宣告、易於使用且容易閱讀

-------------------------------------------------
# (Emma) What is “this” in JavaScript? What does “this” refer to?

## Outline
- Simple call (直接的調用)
- As an object method (物件的調用)
- Arrow Functions (箭頭函式的調用)
- As a DOM event handler (DOM 物件調用)
- Strict mode (嚴格模式調用)
- `call`, `apply`, `bind` (強制綁定 `this` 的調用)


## Simple call
如果直接調用函式，此函式的 this 會指向 window，以下兩個範例都是直接調用函式，所以都是指向 window
#### Example 1: this refers to window object
```javascript=
window.name = 'window';
function callName() {
  console.log('call:', this.name);
}

callName(); //window
```

#### Example 2: 不管在哪裡宣告調用,simple call -> window
```javascript=
window.name = 'window';
function callName () {
  console.log('call:', this.name);

  // function 內的 function
  function callAgainName () {
    console.log('call again:', this.name);
  }
  callAgainName();
}

callName(); //"call:" "window"    //"call again:" "window"
```
小結: ==無論在哪一層，純粹的調用方式 this 都會指向 window==

## As an object method
如果 function 是在物件下被called，那麼 this 則會指向此object，無論 function 是在哪裡宣告
#### Example 1
```javascript=
var age = 18;

var person = {
  age: 28,
  displayAge: displayAge
}

function displayAge() {
    console.log(this.age);
    console.log(this);
}

displayAge(); // 18 //window

person.displayAge(); 
// 28, //{age: 28, displayAge: ƒ}, 在物件下呼叫，this 則是該物件 
```

#### Example 2: 把object裡面的function指給一個變數, 但還是用simple call 
```javascript=
window.age = 18;
var person = {
  age: 28,
  displayAge: function () {
    console.log(this.age);
    console.log(this);
  }
}

//物件內的 function指給一個變數
var callThisName = person.displayAge; 
callThisName(); // 18, window
```

#### Example 3: nested object
```javascript=
window.age = 18;

function displayAge() {
    console.log(this.age);
    console.log(this);
}

var person = {
    age: 28,
    displayAge: displayAge,
    nestedPerson: {
        age:40,
        displayAge: displayAge
    }
}

displayAge();        //18 //window
person.displayAge(); //28, //{age: 28, displayAge: ƒ}. this refers to the person object 
person.nestedPerson.displayAge(); //40 //{age: 40, displayAge: ƒ}. this refers to the nestedPerson object
```

## Arrow functions: they don’t have their “own” this
- 依據語彙環境的父層區域（parent scope）來綁定。白話的說，arrow function **定義位置**（不是呼叫順序）的上一層 this 代表誰，arrow function 內的 this 就代表誰
```javascript=
var person = {
    age:28,
    displayAge:function() {
        const displayAge2 = () => { 
            console.log(this.age);
            console.log(this);
        }
        displayAge2(); //arrow function->parent this
    }
}

person.displayAge(); //28, {age: 28, displayAge: ƒ}
```

## As a DOM event handler
- DOM 搭配 addEventListener 時，this 指的是觸發事件的元素。以下這段程式碼可以貼在任何網頁下的 Console，接下來點擊畫面上任何一區域，該區域則會加上紅線

#### Example 1: DOM + addEventListener, this 是 DOM boject
```javascript=
const box = document.querySelector('.box')
box.addEventListener('click', function(){
    console.log(this); // 這裡的 this 是 DOM box
})
```

#### Example 2: DOM + addEventListener + arrow function, this 是 parent 的 this
```javascript=
const box = document.querySelector('.box')
box.addEventListener('click', function(){
    console.log(this); // DOM box
    setTimeout(()=>{
        console.log(this); // DOM box. arror function->parent this
    },500)
})
```

## Strict mode: 讓simple call的 this 不再是全域 window, 需要給它this
- 現在會建議寫 JavaScript 的時候加入 'use strict'，這可以改正一些coding不良習慣，但也有可以因此導致專案無法運作，此時可以考慮將 'use strict' 加在函式內，避免影響過去的程式碼及相關套件
#### Example 1
```javascript=
window.age = 28;
function displayAge() {
  'use strict';
  console.log('call:', this.age);
}
displayAge();
// Uncaught TypeError: Cannot read properties of undefined (reading 'age')
```

#### Example 2:給 strict mode 一個this, object調用 or 綁定都可以
```javascript=
window.age = 38;
const person = {
  age :28,
  displayAge: function displayAge() {
    'use strict';
    console.log(this.age);
  },
}
person.displayAge(); //28. object call->this is person obj
person.displayAge.call({ age: 18 }); //18. 強制綁this
```

## 強制綁定 this
`call`, `bind`, `apply` 這三者都可以傳入新的 this 給予函式使用，使其作為 this 所指向的物件，三者僅是使用方法不同

#### `call` 
- **`fn.call(this, arg1, arg2..., argn)`**
    - 第一個參數：想要綁定的 this
    - 第二以後的參數：想要傳進目標函式的參數，如果目標函式中不需要參數則不要傳入即可
- 功能
    - 執行 function
    - 明確指定 this

Example 1: 強制綁定18,永遠的18歲！
```javascript=
var age = 28;
function callName() {
  console.log(this.age);
}

callName(); // 28
callName.call({age: 18});  // 18
```
Example 2: 除了傳入給定 this 的參數之外還可以傳入其他argument
```javascript=
var obj1 = {
  myName: 'obj 1',
  fn: function (message) {
    console.log(this.myName + ' ' + message);
  }
}

var obj2 = {
  myName: 'obj 2',
}

obj1.fn.call(obj2, 'Hello'); //obj 2 Hello
```

#### `apply`
- **`fn.apply(this, [arg1, arg2..., argn])`**
    - 第一個參數：想要綁定的 this
    - 第二個參數：與`call`類似, 只是第二個參數是陣列而且必須是陣列
- 功能
    - 同`call`
```javascript=
var obj1 = {
  myName: 'obj 1',
  fn: function (message) {
    console.log(this.myName + ' ' + message);
  }
}

var obj2 = {
  myName: 'obj 2',
}

obj1.fn.call(obj2, ['Hello']); //obj 2 Hello
```

#### `bind`
- **`fn.bind(this, arg1, arg2..., argn)`**
    - 第一個參數：想要綁定的this
    - 想要傳進目標函式的參數，如果目標函式中不需要參數則不要傳入即可
    - 回傳：回傳包裹後的目標函式
- 功能
    - 明確指定 this
    - 回傳一個包裹函式，當我們執行這個函式時，同時將arguments 一起帶進 Function 中
    - 無論函數怎麼被調用，原始函數的 this 在新函數將永遠與 bind 的第一個參數綁定起來, 只能綁一次的概念

Example 1
```javascript=
function fn() {
    console.log(this.a);
}

var bfn = fn.bind({a: 'Mark'});

var b2fn = bfn.bind({a: 'Rose'});

fn(); // undefind, 全域沒有定義a
bfn(); // Mark
b2fn(); // Mark. bind 只能使用一次！就算再綁Rose也沒用
```

Example 2: object call + `bind`
```javascript=
function fn() {
    console.log(this.a);
}

var bfn = fn.bind({a: 'Mark'});

var b2fn = bfn.bind({a: 'Rose'});

var obj = {a: 'John', fn: fn, bfn: bfn, b2fn: b2fn};

obj.fn(), obj.bfn(), obj.b2fn();
// John, Mark, Mark. object調用在bind過後會被取代
```

## 整理
- Simple call: window
- As an object method: object本身
- Arrow Functions: parent this
- As a DOM event handler: DOM object
- Strict mode: 綁進去的this
- `call`, `apply`, `bind`: 強制綁進去的`this` 
- As a constructor: 建構式本身new object

## 總結
- ==Regular function: how is called ?==
- ==Arrow function: where is definded ?==


## Reference
[this: Simple call, Object method, DOM event handler, Constructor](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/this)
[Regular function v.s Arrow function](https://www.youtube.com/watch?v=dWZIPIc3szg)
[Strict mode](https://www.w3schools.com/js/js_strict.asp)
[call, apply, bind](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call)




--------------------------------------
# (Ralph) What is Big O notation?
![](https://i.imgur.com/IGWK0wa.jpg)
![](https://i.imgur.com/JeXl7iM.jpg)
![](https://i.imgur.com/43SH50c.jpg)
![](https://i.imgur.com/O2eBu2Z.jpg)
![](https://i.imgur.com/Lr2DtuK.jpg)
![](https://i.imgur.com/MQ2JANA.jpg)
![](https://i.imgur.com/1ekOibg.jpg)
![](https://i.imgur.com/4Ey8Io1.jpg)
![](https://i.imgur.com/NU3mGN1.jpg)
![](https://i.imgur.com/9UEfEu6.jpg)
![](https://i.imgur.com/q4W7zzP.jpg)
![](https://i.imgur.com/9O669RJ.jpg)
![](https://i.imgur.com/i3B21T1.jpg)
![](https://i.imgur.com/3Ryf3DN.jpg)
![](https://i.imgur.com/D0LuhEM.jpg)
![](https://i.imgur.com/LyuyUyq.jpg)
![](https://i.imgur.com/89JcGRs.jpg)
![](https://i.imgur.com/XkWn3WY.jpg)
![](https://i.imgur.com/eeQPfVS.jpg)
![](https://i.imgur.com/Kyg7x9B.jpg)
![](https://i.imgur.com/LFiY3LC.jpg)
![](https://i.imgur.com/szl4g44.jpg)
![](https://i.imgur.com/7qULYdn.jpg)
![](https://i.imgur.com/yyA1vZG.jpg)
![](https://i.imgur.com/KIuUUw2.jpg)
![](https://i.imgur.com/gwwvWdN.jpg)
![](https://i.imgur.com/eNlVtlT.jpg)
![](https://i.imgur.com/P4ZTn3Q.jpg)
![](https://i.imgur.com/xrEJ1DF.jpg)
![](https://i.imgur.com/WGKOVpL.jpg)
![](https://i.imgur.com/G6n4RSq.jpg)
![](https://i.imgur.com/hk2R5uS.jpg)
![](https://i.imgur.com/TjaVHLV.jpg)
![](https://i.imgur.com/JQ7wk5g.jpg)
![](https://i.imgur.com/6iOAjUv.jpg)
![](https://i.imgur.com/5iYL5yN.jpg)
![](https://i.imgur.com/u7wfpbm.jpg)
![](https://i.imgur.com/Sm6csnj.jpg)
![](https://i.imgur.com/ZqIWSqb.jpg)
![](https://i.imgur.com/q5JpH6p.jpg)
![](https://i.imgur.com/FA9RZzh.jpg)
![](https://i.imgur.com/k6OT2fG.jpg)
![](https://i.imgur.com/vgJKQIg.jpg)
![](https://i.imgur.com/6PoSW1v.jpg)
![](https://i.imgur.com/AFNPT8Z.jpg)
![](https://i.imgur.com/pfXTMZY.jpg)
![](https://i.imgur.com/kNKi7Ql.jpg)
![](https://i.imgur.com/im6Af5k.jpg)
![](https://i.imgur.com/mUoXusR.jpg)
![](https://i.imgur.com/EaZeaFe.jpg)
![](https://i.imgur.com/3xeVFdM.jpg)
![](https://i.imgur.com/Zt6i2QT.jpg)
![](https://i.imgur.com/n6wl32r.jpg)
![](https://i.imgur.com/OuIJBF3.jpg)
![Uploading file..._d99t93it3]()
![](https://i.imgur.com/pdrDZrI.jpg)
![](https://i.imgur.com/ksjn2yd.jpg)
![](https://i.imgur.com/oxzJjEX.jpg)
![](https://i.imgur.com/862nkYu.jpg)
![](https://i.imgur.com/vA7051U.jpg)
![](https://i.imgur.com/mVQZ1TD.jpg)
![](https://i.imgur.com/PcjCUqG.jpg)
![](https://i.imgur.com/OakqGyl.jpg)
![](https://i.imgur.com/ahAQT3c.jpg)
![](https://i.imgur.com/TaQC3sm.jpg)
![](https://i.imgur.com/m2oGKh2.jpg)
![](https://i.imgur.com/GO5kKNt.jpg)
