---
# System prepended metadata

title: 各式各樣學習分支
tags: [學習筆記, 物件導向]

---

# 各式各樣學習分支
###### tags: `學習筆記` `物件導向`

## 建構函數 & Class 的區別
參考來源 : 
>[ ES6 中最容易誤會的語法糖 Class - 基本用法](https://medium.com/enjoy-life-enjoy-coding/javascript-es6-%E4%B8%AD%E6%9C%80%E5%AE%B9%E6%98%93%E8%AA%A4%E6%9C%83%E7%9A%84%E8%AA%9E%E6%B3%95%E7%B3%96-class-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95-23e4a4a5e8ed)
[物件導向 JavaScript (object-oriented JavaScript)](https://pjchender.dev/javascript/js-oo/)
[繼承與原型鍊 - 使用 Object.create 建立多層繼承](https://israynotarray.com/javascript/20210221/2645303265/)
[關於 Object ，一口氣全說完](https://medium.com/enjoy-life-enjoy-coding/javascript-%E9%97%9C%E6%96%BC-object-%E4%B8%80%E5%8F%A3%E6%B0%A3%E5%85%A8%E8%AA%AA%E5%AE%8C-4bb924bcc79f)

>JavaScript使用 **建構式函式(constructor function)** 來定義物件和他們的特色，
>例如: function Person() {};
>用開頭大寫來區分是一般函式還是**建構式函式(constructor function)**，沒辦法很清楚的分辨
>現在直接用 **ES6 語法糖 class** 搭配 constructor () {}; 就能清楚的分辨。
>可以看做是 function Person() {} = constructor () {};
- constructor 擁有 prototype 屬性。
- class 沒有 hoisting 的機制。
```javascript=
Class Person {
    constructor(name) {
        this.name = name;
    }
    
    // 這個 getInfo 會直接變成 Person 的 prototype (原型)
    getInfo() {
        const state = 'Taiwan';
        return `${this.name} is from ${this.state}`;
    }
}
```
### **class 的繼承 extends**
參考資料來源 : 
> [JavaScript ES6 class 關鍵字](https://www.fooish.com/javascript/ES6/class.html)

- 繼承時如果有 consturctor 要用，必須調用 super() 否則會出錯。
- 繼承時如果有 consturctor ，必須調用 super() 後才能引用 this 否則也會出錯。
- 當作物件 super 也可在一般方法中使用，用來引用父類別的方法和屬性

> 這是因為在 ES6 中，是先建立父類別 (parent class) 的物件實例 this 所以必須先執行 super()，然後再用子類別的 constructor 修改 this。
> 透過 super 調用父類別的方法時，super 會綁定子類別的 this
> (**原先父類別方法裡面用到 this 的會指向子類別**)
```javascript=
class Car {
    constructor() {
        console.log('Creating a new car');
    }
}

class Porsche extends Car {
    constructor() {
        super(); // 這個 super 就是調用 Car 的建構函數(constructor)
        console.log('Creating Porsche');
    }
}

let c = new Porsche();

// 依序顯示
// Creating a new car
// Creating Porsche
```
- super 關鍵字有兩種用法：
  1. 當作函數 super()，只能在子類別的 constructor 中使用，在其他地方用會報錯
  2. 當作物件 super，在一般方法中使用，用來引用父類別的方法和屬性
> 第二種用法，透過 super 調用父類別的方法時，super 會綁定子類別的 this (而不是父類別的 this)

---
## 使用 **new** 建立實例步驟 ==可以再多看看其他人怎麼寫==
參考資料來源 : 
> [JS 的 new 做了哪些事情呢？](https://juejin.cn/post/6968856664560648199)

```javascript=
function Person(name,age) {
    this.userName = name;
    this.userAge = age;
}

var personl = new Person('LULU',20)
```
1. 創建一個空對象。

```javascript=
let obj = {};
```
2. 設置原型鏈。
```javascript=
obj.__proto__ = Object.create(Person.prototype);
```
3. 將建構函式的 this 指向新對象 obj 並執行函數代碼。
```javascript=
let result = Person.apply(obj, arguments);
```
4. 如果建構函式 return 一個 object 類型，那麼返回此變量，否則返回空對象
```javascript=
typeof(result) === 'object' ? result : obj;
```

---

# **call() & apply() & bind()**
參考來源 : 
>[call,apply,bind, function currying (科里化), function borrowing (函式借用)](https://medium.com/itsems-frontend/javascript-bind-call-apply-and-function-borrowing-and-currying-6bed787cd3eb)

### **call() & apply() 差別在於第二個參數以後**
 - 第一個參數 : 指定 **this** 對象
 - 第二個以後的參數 : call 為==一個一個==參數帶入 ，apply 為參數==陣列==帶入
 - 直接執行函式

### **bind()** 綁定 this 對象後回傳新的函式
 - 第一個參數 : 指定 **this** 對象
 - 第二個以後的參數 : 看要不要指定參數值，可給可不給
 - 不會執行函式，回傳新的函式

==科里化== 「**將接收 n 個參數的函式拆解為一連串 n 個只接受一個參數的函式**」
科里化使用 .bind(this) ，用 this 指向自己這個函數，相當於閉包作用， this 後面的參數看是否要指定數值
```javascript=
function add(a, b) {
    return a + b;
}

const add10 = add.bind(this, 10);

// 這時候 add10 相當於
function add10(b) {
    // this 後的參數指定 a = 10;
    const a = 10;
    
    // return 用 this 指向自己的 add 函式(閉包的功用)
    return function add(a, b);
}

add10(5); // 15
add10(7, 4) // 17 後面的參數 4 就沒有帶進去函式裡面使用了
```
---
## **this**
參考資料來源 : 
>[JavaScript this 的用法](https://shubo.io/javascript-this/)

this 的值，是在被呼叫的當下才會決定的。
this 就是當時呼叫這個方法的物件。
沒有物件的時候 this 的值會是 **window**，或是 strict mode 底下的 **undefined**。

**Arrow function (箭頭函式)** 的 this，沒有自己的 this, 他的 this 會等於被宣告當下所在環境的 this。
**結論 : 
this 就是呼叫方法時，「點」前面的那個物件。
而箭頭函式沒有自己的 this， 他的 this 由外層的環境決定。**


> 沒有物件時使用 this 如果是在瀏覽器環境下相當於在 window 物件下使用 this，所以 this 的值當然就是 window。
> 瀏覽器中可以用 "use strict"; 的語法開啟嚴謹模式，可以讓一些不良的寫法拋出錯誤。