**Tip**
```js
.call() -> 第一個參數可以指定 this 的指向,第二個以後的參數為原函數的參數
.apply() -> 與 call() 相似,只是第二個以後的參數需要用 [] 包住
.bind() -> bind 使用參數的用法與 call / apply 類似,只是他不會馬上執行
而是回傳一個依照參數而修改的新函數,這邊回傳的新函數會將 hi() 的 a 代為 1
這稱為 "partial function 偏函數" 可以先代入一部分的引數進去成為一個新函數
optional chaining operator -> 指的是如下面的"?",意思是不確定 person 這個實體裡面
是否有一個 key 為 pet,如果有就繼續下去執行 pet.family,
如果沒有則停止並回傳 "undefined" 防止程式出錯
person.pet?.family
```
**recursive 遞迴**
```js
function fib(n){
if( n === 0 || n === 1 ){
return n
}
return fib( n - 1 ) + fib( n - 2 )
}
// 可以在本身的函數中呼叫本身函數卻不會堆疊爆炸是因為使用了遞迴,
// 因為函數最終會有個止點
// ( 在上面的範例中就是當 n = 0 || 1 的時候 )
```
**this**
this 指的是一個代名詞,在不同的情況下 this 指向會有不同
1. 誰呼叫,誰就是this
2. 沒人呼叫,this 就是指全域物件 ( window / global )
3. 是否有使用 new
4. 是否有使用箭頭函數 ( 因為箭頭函數沒有 this )
5. 是否有使用 call 或 apply 或 bind
6. 是否有啟用嚴格模式 "use strict"
e.g.
1. 誰呼叫,誰就是this
```js
const hero = {
name: "A",
attack: function(){
console.log(this)
}
}
hero.attack()
// 這邊 hero 呼叫了 attack 這個 function,所以根據第一個規則
// 這邊的 this 會印出 hero {name: 'A', attack: ƒ}
```
2. 沒人呼叫,this 就是指全域物件 ( window / global )
```js
function hi(){
console.log(this)
}
hi()
// 這邊則是因為沒有人呼叫 hi 這個 function ( 其實這邊 hi() === window.hi() )
// 所以根據第二個規則,this 會印出全域物件 window
```
3. 是否有使用 new
```js
const heroCreator = function (name, age){
console.log(this)
// 第一次印出 this
this.name = name
this.age = age
console.log(this)
// 第二次印出 this
}
let hero1 = new heroCreator( "cc", 18 )
// 這邊因為走 new 的方法產出 hero1 會先把 this 指定一個空物件{}
// 再將 name = "cc" 以及 age = 18 導入進空物件中
// 所以這邊第一次印出的 this 就會是一個空物件 {}
// 第二次印出的 this 就會是 {name: 'cc', age: 18}
```
4. 是否有使用箭頭函數 ( 因為箭頭函數沒有 this )
```js
const heroCreator = (name, age) => {
console.log(this)
// 第一次印出 this
this.name = name
this.age = age
console.log(this)
// 第二次印出 this
}
let hero1 = heroCreator( "cc", 18 )
// 這邊要注意因為箭頭函數內沒有 this,所以無法使用 new 來創建
// 所以 heroCreator 裡面的 this.name 與 this.age 無作用
// 然後因為箭頭函數內沒有 this 所以這邊第一次與第二次印出的 this 會往外找
// 這邊因為往外就是最外層也就等於會指向全域物件
```
5. 是否有使用 call 或 apply 或 bind
```js
const hero = {
name : "cc",
age : 18
}
function hi( a, b ){
console.log( a, b )
console.log( this )
}
hi()
// 原本這邊印出的 this 會指向全域物件 window / global
hi.call(hero, 1, 2)
// 但用了 .call 這邊第一個參數會強制綁定 this 到 hero,第二個參數之後的則代入原參數
// 所以這邊印出的 this 會是 hero {name: 'cc', age: 18}
hi.apply(hero, [1, 2])
// apply 與 call 效果相似,差別只為第二個參數之後的必須用[]包住
hi.bind(hero, 1)
// bind 使用參數的用法與 call / apply 類似,只是他不會馬上執行
// 而是回傳一個依照參數而修改的新函數,這邊回傳的新函數會將 hi() 的 a 代為 1
// 這是一種 partial function 偏函數,可以先代入一部分的引數進去成為一個新函數
```
6. 是否有啟用嚴格模式 "use strict"
```js
function hi() {
"use strict"
console.log(this)
}
hi()
// 如果有用嚴格模式,則會限制住 this 往外指向全域物件
// 這裡的 this 會因為嚴格模式導致找不到而印出 undefined
```