# 各式各樣學習分支
###### 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"; 的語法開啟嚴謹模式,可以讓一些不良的寫法拋出錯誤。