# 0416 Stack/Queue, 物件導向, this
###### tags: `JavaScript`
## 大綱
- 作業檢討
- [stack vs. queue](#Stack_vs._Queue)
- [物件導向](#物件導向)
- [this(完整版)](#this(完整版))
---
## 作業檢討
### JavaScript 的變數範圍
```javascript=
var a = 1
function hello() {
a = 2
var a = 3
console.log(a);
}
console.log(a); // 會印出什麼?
hello() // 會印出什麼?
console.log(a); // 會印出什麼?
//答案
// 1
// 3
// 1
```
### 費波那契數列
```javascript=
function fibonacci(n) {
// 實作內容
}
fibonacci(100) // 可在畫面上印出小於 100 的數列
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
```
- 龍哥作法:
```javascript=
function fib(n) {
let [prev, current] = [0,1]
let result = []
while(current <= n) {
result.push(current);
[prev, current] = [current, prev + current]
}
return result
}
console.log(fib(100))
```
---
## Stack_vs._Queue
- [瘦瘦但很厲害的男生解釋](https://www.youtube.com/watch?v=8aGhZQkoFbQ)
- [那個男生做的視覺化說明網站](http://latentflip.com/loupe/)
- ==JS 是一個單執行緒(single thread)的語言==
- 等一個程序執行完再繼續下一個
- 一個一個往下執行
- 只要有程序執行就會拿一個 Stack,直到程序結束才會拿掉 Stack
```javascript=
function a() {
console.log('a')
}
function b({
console.log('b1')
while(true){ // 無窮迴圈
}
console.log('b2')
})
b()
a()
// 僅會印出 b1
// 然後進入無窮迴圈無法自拔
```
- 通常 Stack 都會有個極限


```javascript=
setTimeout(() => {
console.log('hi')
}, 1000
) // 1000 ms(毫秒)-> 1秒, 之後執行 console.log('hi')
```
```javascript=
setTimeout( function, 時間/毫秒 ) // 經過時間後才執行function
```
- 非同步執行的 function (Queue 的使用)
```javascript=
function b () {
console.log('b')
}
b()
setTimeout(() => {
console.log('hi')
}, 0
) // 1000 ms(毫秒)-> 1秒, 之後執行 console.log('hi')
b()
// 'b'
// 'b'
// 'hi'
```
- 如果 Stack 中有 ==非同步執行== 的 function => 直接被丟到 WEB API 裡面處理時間問題
- WEB API 時間條件滿足 => 被丟到 Callback Queue 裡排隊
- Queue 內 function 執行條件:Stack 被清空
- 會被丟進 WEB API 的 function: .addEventListener, .setTimeout
* Stack:Last In First Out (LIFO) 後進先出
* Queue:First In First Out (FIFO) 先進先出
### *面試題:
```javascript=
setTimeout(
() => {console.log('hi')},
3000
)
```
解釋:「最快三秒之後出現 hi 」
---
## 物件導向
- 原生 JS 無 class 寫法
- 但是 JS 是一個真正 ==物件導向== 的程式語言
- [JavaScript 考古題](https://github.com/lydiahallie/javascript-questions)
### JavaScript 中 Object 指向記憶體位置的特性:
```javascript=
let a = {
name: 'kk',
age: 18
}
console.log(a) // { name: 'kk', age: 18 }
let b = a
//此時的 b 跟 a 指向同一個東西
b.name = 'cc'
// b 做了修改,但因為 a 跟 b 指向同一個東西,所以 a 跟 b 就會印出同樣的結果
console.log(b) //{ name: 'cc', age: 18 }
console.log(a) //{ name: 'cc', age: 18 }
```
---
### 在 function 裡面改變 object 裡面的值
- 產生 side effect
- const 常數定義:不能 re-assign
- 但是只要殼 (記憶體位置) 沒換,就可以在裡面做修改
* 宣告 function 後再宣告 function 對應到的 Object
```javascript=
function a () {
var x = 1
}
a.hello = 123
console.log(a) // [Function: a] { hello: 123 }
console.log(a.hello) // 123
```
```javascript=
const user = {
name: 'kk'
age: 18
}
Object.freeze(user) // 把 user 凍~凍~起來 🥶
user.age = 30
console.log(user)
// 18
```
```javascript=
const user = {
name: 'kk'
age: 18
}
Object.freeze(user)
const c = user
c.age = 30
console.log(user)
console.log(c)
// 18
// 18
```
- 使用 `Object.create()` 創造新的 Object,再指定 Key-Value 給它
```javascript=
const u1 = {}
const u2 = Object.create(null)
u2.age = 18
console.log(u1) // {}
console.log(u2) // [Object: null prototype] { age: 18 }
```
---
### 宣告時用 function 回傳的 Object
- JavaScript 中如果變數名稱帶入時 Value 跟 Key 相同 => 可以只寫 Key
```javascript=
function heroCreator(name, power) {
const hero = {
name, // 如果key & value 一樣,只要輸入一個就好 等於 name: name
power, // 等於 power: power
attack: function() {
console.log('Attack!')
}
}
return hero
}
const goku = heroCreator('悟空', 500 )
console.log(goku) //{ name: '悟空', power: 500 }
goku.attack() // Attack!
```
- 創造類似於 Ruby 類別模組的概念,讓利用 function 宣告的 Object 都可以使用一樣的 function
```javascript=
function heroCreator(name, power) {
const hero = {
attack: function() {
console.log('Attack!')
}
}
return hero
}
const goku = heroCreator('悟空', 500)
const gohan = heroCreator('悟飯', 50)
goku.attack() // 'ATTACK'
gohan.attack() // 'ATTACK'
```
- 在 Ruby 中常使用的類別方法
```ruby=
class Cat
def aaa
end
end
kitty = Cat.new
minny = Cat.new
kitty.aaa
minny.aaa
```
---
### Prototype Chain 原型鏈
- `Object.create(a)` => a 只能為一個原型 Object 或是 null
- 幫忙串接原型鏈
- 借某個物件當原型創造一個新物件
- 目的:共享特定功能
* Overview
```javascript=
const heroActions = {
attack: function() {
console.log('ATTACK')
}
}
const goku = Object.create(heroActions)
const gohan = Object.create(heroActions)
console.log(heroActions) // {attack: function}
console.log(goku) // {}
// 透過現有物件打造一個新的物件
// goku 本身沒有任何 function,只是串起原型鏈所以可以使用原型上的 function
goku.name = '悟空'
console.log(goku) // {name: '悟空'}
goku.attack() // 'ATTACK'
gohan.name = '悟飯'
console.log(gohan) // {name: '悟飯'}
gohan.attack() // 'ATTACK'
//目的:共享attack功能
goku.attack = 3 // 把 goku 上的 attack 改掉 (呼叫時會先找該物件上的東西)
goku.attack() // error: goku is not a function
gohan.attack() // 'ATTACK' 原型的功能還是會在,不會被更動
```
- 用原型創造出來的 Object 上附帶的功能還是會對應到原本的位置
- 從創造出的 Object 上呼叫功能時 => 會順著原型鏈找功能
- 如果原型上的功能被改掉 => 從創造物呼叫時一樣會對到被改掉的功能
```javascript=
const heroActions = {
attack: function() {
console.log('ATTACK')
}
}
const goku = Object.create(heroActions)
heroActions.attack = 1 // 改動原型上的功能
goku.attack() // 出錯 'attack is not a function'
```
- 理解完之後還是會用 class (實務上也都是這麼用)
```javascript=
class Hero {
constructor (name, power) {
this.name = name
this.power = power
}
attack () {
console.log('ATTACK: ' + this.power)
}
}
```
- 串接原型鍊
```javascript=
const heroActions = {
attack: function() {
console.log('ATTACK');
}
}
const goku = Object.create(heroActions) // 串起原型鏈的動作
console.log(goku) // {} 因為僅只是串起原型鏈,尚未宣告任何其他值
goku.attack() // 'ATTACK' 執行功能時會先找 goku(找不到) =連結到heroActions找=> 執行
```

```javascript=
const heroActions = {
attack:
}
function heroCreator (name, power) {
const hero = Object.create(heroActions),
name,
power
}
```
#### 有沒有 new 差很多
- 沒有 new :
```javascript=
function heroCreator(name, power) {
this.name = name // this -> 全域變數
this.power = power
// 沒有回傳值
}
const h1 = heroCreator('悟空', 500)
console.log(h1)
// underfined
```
- 有 new:
- 在新的物件裡面加上 this 空物件,再把 this 回傳
- ==會影響 this 的指向範圍==
```javascript=
function Hero(name, power) {
// this = {} 甭自己寫
this.name = name
this.power = power
// return this 甭自己寫
}
const h1 = new Hero('悟空', 500) // 透過function產生物件要用 new
console.log(h1)
// Hero { name: '悟空', power: 500 }
// 前面的 Hero 只是一個標記,不用理他。新的 h1 就是一個物件
```
---
```javascript=
const obj = []
console.log(obj.length)
```
每個物件都有特別的屬性(`.__proto__`)
屬性會一個接一個連過去到找不到 ( `null` ) 為止
```javascript=
obj.__proto__ //底線底線
```
每個 function 都有 `.prototype`
因為 function 也是物件所以 function 有 `.__proto__` 也有 `.prototype`
```javascript=
function a() {
var x = 1
}
a.hello = 123
console.log(a)
//
```
所有 function 的 prototype 都是一個空物件 ({ })
```javascript=
a.__proto__ 指向 生他的 function.prototype
```
- JavaScript 的 boxing / unboxing
```javascript=
a = 1
a = Number(1).__proto__ // 不確定對不對
```

箭頭函式不會有引數(argument
全域變數的回傳值是 undefined
全域變數上的任意屬性是 undefined
## this(完整版)
[new & proto](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new)
```javascript=
const obj = {
name: 'kk',
age: 18,
a: function() {
console.log
}
}
```
### .bind()
```javascript=
function a() {
console.log(this.age)
}
const user = {name: 'kk', age: 18}
const user_a = a.bind(user)
// a.bind(user) => .bind 會回傳一個新的 a function 然後以 user 為 this
user_a()
// 18
```
### .call() / .apply()
```javascript=
function a() {
console.log(this.age)
}
const user = {name: 'kk', age: 18}
a.call(user)
a.apply(user)
// 18
```
- .call()跟.apply()都會呼叫A,然後把第一個參數當成 this(改變 this 的指向)
- 第二個之後的參數才會變成真正的參數帶入原始 function 裡
```javascript=
function a(x) {
console.log(x)
}
const user = {name: 'kk', age: 18}
a.call(user)
a.apply(user)
a.
// 18
```
this 跟所放的位置無關,看他在哪裡被呼叫(被誰呼叫),this 就是誰
```javascript=
var hero = {
name: '悟空',
sayMyName: function() {
console.log(this.name);
}
};
hero.sayMyName(); // A 悟空
var speakOut = hero.sayMyName;
speakOut(); // B undefined 沒有人呼叫speakOut
// this = 全域物件 / 全域物件.屬性 = undefined
const someone = { name: '路人' }
hero.sayMyName.call(someone); // C 路人
function here() {
console.log(this);
}
const there = () => {
console.log(this);
}
here(); // D 沒有人呼叫 = 全域物件
there(); // E 沒有人呼叫 = 全域物件
```
### 口訣:
- 規則 1. 函數執行的時候,有沒有使用 new 關鍵字?如果有,this 就是指向那個物件本身。
- 規則 2. 「誰呼叫,誰就是 this」規則。
- 規則 3. 是否使用箭頭函數?有的話就不會有自己的 this。
- 規則 4. 是否有使用 bind、apply 或是 call 方法?有的話 this 的指向也會跟著改變。
- 規則 5. 是否有開啟「嚴格模式」?
### 嚴格模式? 'use strict'
- 向下相容的關鍵字處理
- 使用字串放在第一行就會有嚴格模式的效果
- 如果瀏覽器(IE?)看不懂字串,就不會執行嚴格模式
---
## 題外話
### JS 規則手冊
- 有空可以研讀,收穫會很多,但是很硬
- [JS規則書 : ecma262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/)
### `.push()`的回傳值
- JavaScript 中 `.push()` 的回傳值為新陣列的長度
- [手冊說明](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
```javascript=
let a = ['a', 'b', 'c', 'd']
let b = a.push('x')
console.log(b) // 5
console.log(a) // ['a', 'b', 'c', 'd', 'x']
```
---
### `for` 迴圈補充
- for 迴圈在每次通過驗證式之後都會執行結束動作
- 執行完結束動作後如果不能通過驗證式就會跳出迴圈
```javascript=
function a() {
console.log('a')
}
function b() {
for(var a = 1; a < 10; a++){
}
console.log(a)
}
b()
// 10
// 因為在 a = 9 迴圈結束時執行 a++ => a = 10 => 不能通過驗證 => 跳出迴圈
// 此時 a = 10
```
---
### `typeof`
- `typeof` 方法:以==字串==形式回傳對應的資料型態
- [MDN typeof](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/typeof)
```javascript=
typeof 1
// 'number'
typeof 2
// 'number'
typeof 'a'
// 'string'
typeof []
// 'object'
typeof {}
// 'object'
typeof true
// 'boolean'
typeof null
//'object'
typeof undefined
//'undefined'
typeof(typeof(1))
// 'string'
```
---
### `parseInt` 能將輸入的字串轉成整數
- [MDN parseInt](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/parseInt)
```javascript=
parseInt(string, radix);
```
---
### `!`
```javascript=
```
---
### JS 裡的 `false`
- [MDN falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)
- 規則需要背
- 規則有列的都是假的,沒列的都是真的

```javascript=
// 在終端機內輸入 $ node
> var c = new Boolean(false)
// undefined <- 回傳值
> c
// [Boolean: false] <- 物件
> if (c) {console.log('aa')}
// aa
// c 是物件 是個true
```
- 純量值沒有方法,要使用方法要先把量值物件化之後再使用方法
```javascript=
> Number(1).toString()
// '1'
> 1.toString()
// 1.toString()
//^^
// Uncaught SyntaxError: Invalid or unexpected token
```
---
### 等於的種類
- `===` 比較類型 / 嚴格模式
- `==` 比較值 / 較鬆散
- `=` 宣告、指向
---
### 非同步執行

```javascript=
console.log ('123')
setTimeout(
() => {console.log('hi')},
0 // 雖然只有0秒,但還是會去排隊,等下面的執行以後才會出現
)
console.log ('456')
======>
'123'
'456'
'hi'
```
---
### 開發方法
#### 看板方法(敏捷開發)
- 找個小黑板
- 分成三個部分:To do - Doing(WIP) - Done(FJ)
- 用便利貼建立任務 => 票
- 建議一個人只能接一張票
- 建議一張票只能一個人做
- 適時利用 Trello, GitHub projects 功能... 等工具輔助
|To Do|Doing|Done|
|---|---|---|
|票票票|票票票|票票票|
- 任務挑選:
- 可以選擇挑戰型任務試試看
- 路障型任務
- 快手做?比較慢的人做?
- 可以讓新手試試看,但要設立停損點
- 建立任務點數機制
- 點數 1 ~ 5 ,劃分任務難度
- 注意點數應該呈現常態分配 ( 3點多一點比較好 )
- 如果發現點數往 4 ~ 5 靠攏 => 將任務再做拆分
- 可自行設定 1點 花費多少時間製作去推算
- 每個人可以提出自己對點數的看法,再來討論為什麼跟背後的原因並確認每個人對任務的了解
- 計算專案總計點數及每個人單日可使用點數
- 利用燃盡圖輔助計算任務完成時程
- 算出斜率後可畫出是否會超過 Demo Day
- 超過 => 刪除功能、調整點數、加人
- 燃盡圖波動時即時確認是否超出預設燃盡圖的線段
- 衝刺期
- 用燃盡圖輔助
- 可利用任務點數及每人單日可完成的點數計算整個任務時程