# JS(6/10) Day 20 五倍紅寶石(第八屆共筆)(2021/7/23)
物件:
用 Object.keys (變數名稱)、Object.values (變數名稱)可印出所有 key 跟 value。
在物件裡面的函式會稱作方法,在外面就叫函式。
## 閉包(closure):
一種特性,當使用高階函式時,可以將外層函式裡宣告的變數&值保留到內層函式使用。
```=js
// 外層函式 = a
function a() {
var x = 123
// closure 閉包
// 內層函式 = setTimeout
setTimeout(() => {
console.log(x)
}, 1000)
}
a()
```
結論:x 本來會隨著外層的泡泡破掉而消失,但 JS 卻能把 x 一起帶到 WebAPI 排隊。
過程:(網路上統整的結果,如有寫錯還請同學更正,感謝)
一開始 JS 會先建構全域執行環境、分配記憶體給函式及變數、建構函式及宣告變數&賦值。
=> function a & setTimeout 、 var x = 123 及 console.log(x) 的 x 都會被建立起來。(console.log(x) 的 x 會因為 scope chain 的關係先在內層找有沒有宣告 x ,因為找不到所以往外層找,最後找到 var x = 123,所以內層的 x 會指向外層的 123)
再來會建構 function 的執行環境以及執行程式碼。
=> 呼叫 function a ,建構 a 的執行環境,將 x 儲存在 a 的執行環境。
=> 準備執行 setTimeout ,外層 a 的泡泡破掉,此時 var x = 123 因為一開始有被分配到記憶體,所以還會留在原地,不會跟著泡泡破掉而消失。
=> 執行 setTimeout,x 能夠指向外層的 123,不會變成not defined。
---
### 高階函式(HOF):
很好用,= 函式製造機,可以生出函式出來。
ex:3D列印機可以印出自己出來。
## 物件導向(Object-oriented):
其實就是生物分類法,希望把共同的特性寫在前端,讓後端的物件能直接使用前端的特性。
=> 我只要在前端寫一次,後端的東西就能夠使用,相當方便,不然如果後端的東西有100個的話就要寫100次,太累。
物件 = 屬性 + 行為
屬性:名詞
行為:動詞(function)
繼承 = 分類:可以讓子類別的東西使用上層類別(Super Class、Parent Class)的東西
建構函數:
function 如同{ }可以用來建構物件,把他當成一般物件來用可以做到以下的事。
```=js
function heroCreater(name, action) {
const attack = () => {
console.log(`${name}使用絕招${action}`)
}
return {
name,
action,
attack
// 當參數和屬性同名時,可省略值不寫
// 原本應該長成 name: name,
}
}
const h = heroCreater("小傑", "剪刀石頭石頭")
h.attack()
// "小傑使用絕招剪刀石頭石頭"
console.log(h)
// [object Object] {
// action: "剪刀石頭石頭",
// attack: () => {
// window.runnerWindow.proxyConsole.log(`${name}使用絕招${action}`)
// },
// name: "小傑"
// }
console.log(h.action)
// "剪刀石頭石頭"
```
### 產生空物件:
有兩種方法可用。
1. const a = { }
2. const b = Object.create(null)
=> 利用指定的原型(prototype)把東西灌進去。
重要觀念:
1. 所有的物件都有__proto__屬性
使用後可以找到他的原型。
2. 所有的 function 都有 prototype 屬性
預設的 prototype = { }。
.map 方法其實是 prototype 裡面的屬性,後面的值是 function,用來做事。
```=js
// 對 prototype 物件新增 attack 屬性,值是後面的 function
Hero.prototype.attack = function() {
console.log("attack")
//
}
```
原型鏈(prototype chain):連續使用__proto__可以一層一層往上找到原型。
正常來說印出沒有的屬性應該要會得到 Error,但在 JS 會得到 undefined,
而印出沒有的屬性並呼叫會得到 TypeError,因為呼叫 undefined, undefined 不是 function,會出錯。
```=js
// 建構函數,通常會把函數名稱的首字改成大寫 hero => Hero ,方便辨識這是物件不是函數。
// 這邊的 Hero 稱為建構子,函式前面有 new 的都叫建構子。
function Hero(name, action) {
// new 做的事情
// 1. 建立一個空物件
// 2. 把 this -> {}
// 3. 把 this.__proto__ -> Hero.prototype ( 預設值: { } )
// 4. 自動 return this // 不要自己多寫 return,如果是物件會覆蓋掉 this 值
this.name = name
this.action = action
}
```
```=js
function hello() {
console.log("hi")
}
const h = new hello()
console.log(h)
// hello { } ,裡面的 this = 函式名稱 + 空物件
console.log(this)
// { } ,外面的 this 空物件
---------------------------
const h = hello()
console.log(h)
// undefined,沒有 return 值
```
.map的來源:
list.map 一開始會找不到,因為 list 沒有 map 方法可用
=> 往.__proto__找,但因為 new 的關係會自動轉向到.prototype
=> prototype 裡面有 map 方法
=> 最後會找到 list.prototype.map
```=js
const list = [1, 2, 3, 4, 5] // 左邊跟 list = new Array(1, 2, 3, 4, 5) 是一樣的東西
list.__proto__ === Array.prototype // true
list.__proto__.map === Array.prototype.map // true
```
所有的 function 都有回傳值,當沒有寫 return 時會有兩種預設值:
1. 一般的 function 會回傳 undefined
2. 使用 new 建立的 function 會回傳 this 的值
## class
ES6才有的語法糖衣,本質上還是使用__proto__去做事。
class => new => instance(實體)
(烤盤) (透過) (雞蛋糕)
如果 new Hero() 想帶引數進去,一定要搭配建構子constructor()使用。
constructor 裡面只放屬性,行為請寫在外面。
```=js
class Hero {
constructor(name) {
this.name = name
}
}
let h = new Hero("奇犽")
console.log(h)
```
```=js
class 靈長類 {
squash() {
console.log("!!!!");
}
}
// 黑猩猩是一種靈長類
class 黑猩猩 extends 靈長類 {
}
class 人 extends 靈長類 {
}
me = new 人()
me.squash()
you = new 黑猩猩()
you.squash()
```
---
###### tags: `JavaScript`