Javascript - 從零開始 Day1

第一天

你不可不知的那些小事情 - 生態現況與基本常識

敘事與程式的關係

故事 1:
角色:
Alex => father
Howard => son
故事:
Howard => 肚子餓 => 叫爸爸 => Alex 煮飯

1
2
3
4
5
Howard.addEventListener(肚子餓,叫爸爸)

叫爸爸() {
Alex.煮飯
}

ECMAScript vs JavaScript

LiveScript 跟風 Java 改名 JavaScript

ECMAScript 是規範版本的名稱 Ex : ECMAScript 6

網頁三腳督

HTML + CSS + JavaScript

Javascript 負責事情 1.功能操作 2.動畫 (能用 Css 做就用 Css 做)css 效能比較好用 3.資料處理

BOM vs DOM

BOM(Browser Object Model):操作瀏覽器
Ex: window.navigator , window.location … 等

DOM(Document Object Model):操作網頁內容(大部分是標籤)
Ex: div, style … 等 tag
資料處理
一般在撰寫上要考量要操作哪部分

範例 1

JavaScript 寫在哪裡? 都可以?
位置:

  1. HTML 外面
  2. HTML 裡面
  3. HTML 裡面 HEAD 裡面
  4. HTML 裡面 BODY 裡面

瀏覽器會將上面全都拉近 BODY 裡面 => 建議放在 BODY 結束前

script 包出一個區域做撰寫程式地方
依照順序由上到下的方式去依序執行

最基本類型

  1. 文字 String
  2. 數字 Number
  3. 布林 Boolean
  4. 空值 Null
  5. 未定義 Undefined

如果 HTML 畫面完成再執行 document.write,會把整個畫面清掉從 write

範例 2

1.宣告:新增(取名字) 2.先宣告後使用! (重要
3.var(可改變) let(可改變) const(常數不會變) 4.資料轉換 5.作用域

1
2
3
4
5
6
7
var a = 123; // 宣告 a 變數 等於 123

// 宣告 a 變數,將 123 設定到 a 變數 //

a = 2;

console.log(a); //在console 面板印出內容

a += 2;(簡寫) => a = a + 2;(完整) //在不熟的狀態下不要用簡寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//作用域範圍
//建議使用let方式去宣告 (因為會鎖作用域)
//function作用區塊
function example_var() {
console.log("===== var start =====");
console.log(a); // undefined
var a = 1;
console.log(a); // 1
a += 2;
console.log(a); // 3
console.log("===== var end =====");
}

function example_let() {
console.log("===== let start =====");
console.log(a); // Error 不往下做 註解後可以往下做
let a = 1;
console.log(a);
a += 2;
console.log(a);
console.log("===== let end =====");
}

//常數
function example_const() {
console.log("===== const start =====");
const a = 1;
console.log(a); // 1
a += 2;
console.log(a); // Error 常數不可改
console.log("===== const end =====");
}

let a => undefined //不建議去這樣使用

let a ='' // 預設文字 String
let b =null // 預設物件 Object
let c =0 // 預設數字 Number
let d = false // 預設布林值 Boolean
let e = [] // 預設陣列 Array (有時設 null)

作用域使用

Why 使用作用域 : 因為網頁內容若能被調整, 容易造成網頁內容不安全

  1. block
    es6 使用一對大括號{} =>裡面只能用 let 跟 const
  2. IIFE
    (function(){…})();

function 函式

宣告方式

1.

1
2
3
function 函式名稱(...參數) {
//執行內容..
}

它會有提升 (hoisting) 現象,,像這樣:

1
2
3
4
greet();
function greet() {
//執行內容..
}

2.

  • 優點
    • 函式在宣告時,才產生出來
    • 較符合先宣告後使用的習慣
1
2
3
4
let xxx = function() {
// 宣告一個名稱設定一個function
// ....
};

Chrome & Vscode Tips

Chrome 下斷點

記得要重新整理

vscode 快捷鍵

左方小齒輪 -> 中文 : 使用者程式碼片段 , 英文 : User Snippets

1
2
3
4
5
6
7
8
9
"IIFE": {
"prefix": "iife",
"body": [
"(function() {",
" $1",
"})();"
],
"description": "IIFE"
}

vscode 顯示設定 (專案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"editor.fontFamily": "Fira Code,Microsoft JhengHei",
"editor.fontLigatures": true,

"editor.fontSize": 14, //字體大小
"window.zoomLevel": 3, // 字體縮放大小

"editor.rulers" : [80,120]
"prettier.printWidth": 120 // prettier 換行設定 (幾個字換行)

"explorer.openEditors.visible": 0, // 旁邊檔案開的資料夾數

"files.autoSave": "afterDelay",
"editor.formatOnSave": true,

"editor.tabSize": 2,
"editor.insertSpaces": true,

"emmet.triggerExpansionOnTab": true, //觸發emmet

"liveServer.settings.donotShowInfoMsg": true,
"liveServer.settings.ignoreFiles": [".vscode/**", ".data/**"],
}

Reference

那些該死的運算與轉換 - 資料類型與操作

數學運算與回傳

運算式
運算元(運算的值 ex:數字
運算子(怎麼算 ex:+-=

  1. 賦值運算子 (一般都會改變內容)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a = 1 // 將1賦予a
a += 1 // a = a + 1 => 2
a -= 1 // a = a - 1 => 1
a *= 10 // a = a * 10 => 10
a /= 5 // a = a/5 => 2

//a++ => a +=1 => a = a+1
let b = a++ // 先做b=a (a賦值於b) 後做 a=a+1 a,b = 3,2

let c = --a // 先做 a=a-1 後做 c=(a-1) 此時a-1已先算完,帶入C即可
//a,b,c = 2,2,2

let d1 = b+=1 // b,d1 = 3,3
// 逗號 : 接著做
let d2 = ( b+=1 , c+=2 , a+b+c) // a,b,c,d2 = 2,3,4,9
let d =b+1,c+2,a+b+c // error 這部分切為 let d =b+1 (賦值) / c+2,a+b+c
//除了a++ 這種剩下都是先算完再拿 += 跟++是不相等的
  1. 算術運算子

  2. 字串運算子

1
2
3
4
5
6
7
如果有字串會字串優先;
let x = 1 + "1"; // =>"1"="1"=>"11"
let y = 1 + true; // => 1+1=>2
let z = 1 + !"3"; //=> 1+!true => 1+false=>1+0=>1
//上面會優先做驚嘆號部分 (反轉)
3 + 1 + "2"; //=> 4 + "2" => "42"
3 + (1 + "2"); // => 3 + ("1" + "2") => 3 + "12" => "3" + "12" => "312"

轉換表

if 條件判斷式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 肚子餓

// No.1 => 做事情或不做
如果 肚子餓 => 吃

if(肚子餓){

}

// No.2 => 做a or 做b
如果 肚子餓 => 吃
不然 => 不吃

if( 肚子餓 ) {

}else{
不吃
}

// No.3 => 條件1 做A / 條件2 做B / 做C
如果 肚子很餓 => 吃多一點
不然如果 普通餓 => 吃一點點
不然 不吃

if( 肚子很餓 ) {
吃多一點
}else if( 普通餓 ){
吃一點點
}else{
不吃
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let 肚子 = 40;
let 吃 = function() {
肚子 += 20;
};

if (肚子 < 60) {
吃();
}

console.log(肚子); // 60

if (肚子 < 60) {
吃();
}

console.log(肚子); // 60
1
2
3
4
5
6
7
8
9
10
let 肚子 = 60;
let 吃 = function() {
肚子 += 20;
};

if (肚子 < 60) {
吃();
} else {
不吃(); // 當肚子40不會進來 如果60 會抱錯
}
1
2
3
4
5
6
7
8
9
10
11
12
let 肚子 = 70;

let 客製吃 = function(食物量) {
肚子 += 食物量;
};
if (肚子 <= 40) {
客製吃(40);
} else if (肚子 <= 60) {
客製吃(20);
} else {
客製吃(-10);
}

完整 Code (Alex 版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 肚子餓

let 肚子 = 40;
let 吃 = function() {
肚子 += 20;
};
let 不吃 = function() {
肚子 -= 10;
};
// No.1 => 做事情 OR 不做
//如果 肚子 < 60 => 吃
// if (肚子 < 60) {
// 吃();
// }
// console.log(肚子); // 60

// if (肚子 < 60) {
// 吃();
// }
// console.log(肚子); // 60

// No.2 => 做A OR 做B
//如果 肚子餓 => 吃
//不然 => 不吃
// 肚子 = 60;
// if (肚子 <= 60) {
// 吃();
// } else {
// 不吃();
// }

// console.log(肚子); // 80

// No.3 => 條件1 做A 條件2 做B 做C
//如果 肚子很餓 => 吃多一點
//不然如果 普通餓 => 吃一點點
//不然 不吃

肚子 = 70;
let 客製吃 = function(食物量) {
肚子 += 食物量;
};
if (肚子 <= 40) {
客製吃(40);
} else if (肚子 <= 60) {
客製吃(20);
} else {
客製吃(-10);
}

console.log(肚子); // 60

switch 條件判斷式(進入點)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let 肚子飢餓程度 = 4; // 4,3,2,1
// 沒有break 會一路吃到底
switch (肚子飢餓程度) {
case 4:
console.log("20顆水餃");
break;
case 3:
console.log("三片披薩");
break;
case 2:
console.log("一個便當");
break;
default:
console.log("喝杯飲料");
}
// 刷牙洗臉 => 換衣服 => 穿鞋 => 出門

補充 (二進位 與 Bitwise)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 二進位
// 1:1
// 2:10
// 3:11
// 4:100
// 5:101
let a = 2;
let b = 5;
console.log(a.toString(2), b.toString(2)); // 10,101

// toString(2) -> 2進位的意思

// Bitwise
10 >> 1; // 5 (去小數點除2) // 01010 的全部位元向右移動一位數變成 00101
13 << 1; // 26 //01101的全部位元向左移動一位數變成 11010
13.9 << 1; // 26 (去小數點乘2)
20.8 >> 0; // 20
20.3 << 0; // 20
// >>0 與 <<0 會無條件捨去小數點後面

寫程式建議步驟

1.思考 2.畫圖 3.寫程式

範例 3 window

  1. window.alert ( 跳訊息 )
  2. window.confirm ( 跳確認,回傳布林值 )
  3. window.prompt ( 跳輸入框,回傳輸入內容 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 請輸入你的程式
(function() {
let checkName = window.confirm("願意告訴我名字嗎?"); // true / false
if (checkName) {
// 給
let input = window.prompt("請輸入名字"); // 輸入的內容
customHi(input);
} else {
// 不給
customHi("No Name");
}
function customHi(message) {
// window.alert("Hi!!! " + message);
window.alert(`Hi!!! ${message}`); // ES6 寫法
}
// customHi("Alex");
})();

來人阿!開工吧 - DOM 與事件操作

三劍客

1.Who
2.What
3.When

認識 function 做點事

加上小括號會馬上做
所以在監聽後面不需要加括號
ex: addEventListener("click", greeting);

getElement 與 query

getElement:
1.getElementById (效能較佳,但須考量效率)
2.getElementByClassName => collection (動態更新/無法跑迴圈)
3.getElementByTagName

query:
1.querySelector
2.querySelectorAll => list (靜態不變/有 forEach)

事件

範例 4

1
2
3
4
5
6
7
8
9
10
11
12
function greeting() {
let name = "無名氏";

if (window.confirm("願意告訴我你的稱呼嗎?")) {
// name = window.prompt("請輸入姓名:", "").trim() || name;
// null.trim() => ERROR
let input = window.prompt("請輸入姓名:", ""); // null,""," ","ALEX"," ALEX "
name = (input && input.trim()) || name;
}
window.alert(`嗨,${name}!`);
}
trim => 可以使用這個來去頭尾;

&& / ||

可以拿來做判斷式 , 也能拿來流程控管

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 有不做就不做
case1 true && case2 true // case1 與 case2 都會做 -> 回傳case2 做
case1 true && case2 false // case1做 但 case2 不做 -> 回傳case2 不做
case1 false && case2 true // case1不做 ,case2 做 -> 回傳case1 不做
case1 false && case2 false // case1 與 case2 都不做 -> 回傳case1 不做
// 有中即離開
case1 true || case2 true // case1中即離開 -> 回傳case1 中
case1 true || case2 false // case1中即離開 -> 回傳case1 中
case1 false || case2 true // case1沒中 ,但case2中 -> 回傳case2 中
case1 false || case2 false // case1 與 case2 都沒做 -> 回傳false
// 範例
1&&2&&3 // => 3
1&&2||3 // => 2 // 2 中 且 後面為or運算子 ,即跳開
1&&0||3 // => 3 // 數字0 Boolean為false
1||2&&0 // => 1 後面為or運算子 ,即跳開
3 && 5 //=> 5
3 || 5 //=> 3

範例 5

  1. 程式盡量不要有大量相同的 Code => 整理
  2. 快速大量選取快捷鍵 => ctrl+d (選) ctrl+k(不選)
  3. 怎麼選東西很重要
  4. forEach 參數名稱是自己取的
  5. capture => target => bubble
    滑鼠進入/離開事件
    1.mouseover/mouseout =>
    (1) 在乎的是 Taget (會產生畫面一直跳)
    (2) 會冒泡 (bubble)
    (3) addEventListener 把 useCapture 設 true 就會反向

Target : https://developer.mozilla.org/zh-TW/docs/Web/API/Event/target

2.mouseenter/mouseleave =>
(1) 在乎的是 currentTarget (綁定事件的東西)
(2) 不會冒泡 (bubble)

***根據需要針對對象選擇

字串運算 => 先挖洞在左右補+

1
2
3
4
5
6
7
8
9
10
11
12
// querySelectorAll 迴圈處理
document.querySelectorAll("img").forEach(img => {
img.addEventListener("mouseover", inHandler);
img.addEventListener("mouseout", outHandler);
});

// getElementsByTagName 迴圈處理
let imgs = document.getElementsByTagName("img");
for (let i = 0; i < imgs.length; i++) {
imgs[0].addEventListener("mouseover", inHandler);
imgs[0].addEventListener("mouseout", outHandler);
}

this

  1. 事件偵聽的 this
    who => when =>what
    呼叫事件的人(currentTarget)


圖片的範例
this => bronze currentTarget
(e.currentTarget => 事件綁定的對象)

  1. 箭頭函式沒有 this

  2. this => js 對象

  3. \$(this) => jq 對象

三元運算

1
2
3
4
5
6
7
check ? a : b;

if (check) {
return a;
} else {
return b;
}

current 綁定事件那一個
target 最深那一層的 DOM

mouseenter 不會有 bubble(不會有冒泡)

alex example
***使用 div.id.length 做判斷
=> 思考兩組需要綁定的差異,設定 id 長度不同,所以用這個來做區分

範例 6

  1. 要畫有幫助思考的流程圖(不同事件差異要出來
  2. 迴圈中寫 function 會產生多組重複 function
  3. substr : 切西瓜 (第一刀位置,切多少字)
  4. NodList 沒有 indexOf 要用 […NodeList] 轉成 List
  5. 轉數字 : *1 -0 /1 parseInt()


藍色是正確方式
按(找人) => 換號(依照不同人用不同方式) => 換圖

substr(重哪裡切,切多寬)

當數字超過(過大或過小時)有兩種選擇:下面寫法為第一種選擇
(1) 過大回到 0,過小回到最後 (一種迴圈)
(2) 過大停在最後,過小停在 0 (前後不動)

1.改在 changeView() (改變選圖時)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let imgLength = imges.length;
// 判斷如果imgNumber超過圖片數量就歸0
// 如果沒有再判斷是否有 < 0 則改成圖片長度-1
// 其他就維持不變
imgNumber =
imgNumber >= imgLength ? 0 : imgNumber < 0 ? imgLength - 1 : imgNumber;

if (imgNumber >= imgLength) {
imgNumber = 0;
} else if (imgNumber < 0) {
imgNumber = imgLength - 1;
} else {
imgNumber = imgNumber;
}

2.改在產生 imgNumber 時(改計算時)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// imges.length = 5
// prev
// 4 => 3 => 2 => 1 => 0 => -1(x)
// // 當過少時有兩種選擇
// (1) 回到最後 (4 = imges.length-1)
// (2) 回到開頭 (0)
imgNumber = imgNumber - 1;
if (imgNumber < 0) {
imgNumber = imges.length - 1;
}
// next
// 0 => 1 => 2 => 3 => 4 => 5(x)
// 當過多時有兩種選擇
// (1) 回到開頭 (0)
// (2) 回到最後 (4 = imges.length-1)
imgNumber = imgNumber + 1;
if (imgNumber >= imges.length) {
imgNumber = 0;
}

// 改成取餘數,餘數可以產生數量範圍內的編號
// Ex: 所有數字 / 3 會產生的餘數 = 0,1,2
// Ex: 所有數字 / 5 會產生的餘數 = 0,1,2,3,4
// prev
imgNumber = (imgNumber - 1 + imges.length) % imges.length;
// (0 - 1 + 5) % 5 = 4
// (1 - 1 + 5) % 5 = 0
// (2 - 1 + 5) % 5 = 1
// (3 - 1 + 5) % 5 = 2
// (4 - 1 + 5) % 5 = 3
// next
imgNumber = (imgNumber + 1 + imges.length) % imges.length;
// (0 + 1 + 5) % 5 = 1
// (1 + 1 + 5) % 5 = 2
// (2 + 1 + 5) % 5 = 3
// (3 + 1 + 5) % 5 = 4
// (4 + 1 + 5) % 5 = 0

// 結合 prev 跟 next

1
2
3
4
case "prev":
case "next":
imgNumber = ( imgNumber + (this.id === "prev" ? -1 : 1) + imges.length ) % imges.length ;
break;
1
2
3
4
5
6
7
8
9
10
11
let map = {
prev: -1,
next: 1
};

switch (this.id) {
case "prev":
case "next":
imgNumber = (imgNumber + map[this.id] + images.length) % images.length;
break;
}

== 與 ===

== : 等於
=== : 完全等於

1
2
3
4
5
6
7
8
let a = 1;
let b = new Number(1);

a == b; // true
a === b; // false

typeof a; // number
typeof b; // object

箭頭函式

() => {} // 一行時{}可以省略

1
2
3
4
5
6
7
(msg => console.log(msg))(123);
//((msg) => {console.log(msg);})(123);
// 相當於下面寫法
function print(msg) {
console.log(msg);
}
print(123);

這包東西不簡單 - 陣列與物件的管理應用

一坨與一串東西的特性

資料紀錄

通常無法確認多語系要用哪個語言顯示,盡量使用中性資料 EX:數字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 物件 管理一個對象 (可以指向特定Key Key Value)
let alex = {
name: "alex",
age: 36,
merry: true,
sex: 1
};

let sara = {
name: "sara",
age: 18,
merry: true,
sex: 0
};

// 陣列 管理一串資料 (只能知道先後順序 Index Value)
let family = [alex, sara][
// 0 1

(alex, sara)
].forEach((people, index) => {
console.log(people, index);
});

範例 7

  1. CSR(Client Side Rendom) VS SSR(Server Side Rendom)
    SSR:網頁檢視原始碼看到的(程式產資料)
    CSR:網頁檢視原始碼不一定看得到(資料產程式)
  2. 物件(一根香蕉) VS 陣列(一串香蕉)
  3. 陣列操作
  4. 計時器 setTimeout(做一次) / setInterval(一直做)

資料塞入 DOM => 初始化畫面

麥當勞點餐
現在:點完去旁邊點餐 (非同步
以前:點完好了再下一位(同步

遞迴 => 自己呼叫自己

範例 9

  1. 輸入 => 送出(button) => 抽籤
  2. click(要自己檢查資料) / submit(form 送出)
  3. slice 切出新的陣列 / splice 切原始陣列 (處理陣列)
    slice 不改變原本陣列
    splice 會改變12
  4. split 針對 string 處理切割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let a = [1, 2, 3, 4, 5];
console.log(a.slice(1, 2), a); // [2],[1,2,3,4,5]
// slice 回傳陣列

// 刪除index=1 刪除1個 再index=1插入alex
// (刪除或插入位置,刪除個數,插入資料)
a.splice(1, 1, "alex"); // [1,'alex',3,4,5]
console.log(a);

//split 針對字串
let b = "1,2,3,4,5";
let ary = b.split(",");
console.log(ary); // ['1','2','3','4','5']
let ary2 = b.split("3");
console.log(ary2); // ["'1,2,'","',4,5'"]

你怎麼說我怎麼做 - 條件判斷與流程控制

for 迴圈 vs while 迴圈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let ary = [1, 2, 3, 4, 5];

// For迴圈
let forCount = 0;
for (let i = 0; i < ary.length; i++) {
forCount = forCount + ary[i];
}
console.log(forCount);

// While迴圈
let whileCount = 0;
let temp = [...ary];
while (temp.length) {
whileCount += temp.shift();
}
console.log(whileCount);

// ForEach
let foreachCount = 0;
ary.forEach(num => {
foreachCount += num;
});
console.log(foreachCount);

// 上面都需要宣告一個值才能開始
// Reduce preVal:上次值 ,currentVal:這次值 ,逗號後面是預設值(0)
let reduceCount = ary.reduce((preVal, currentVal) => {
console.log(preVal, currentVal);
return preVal + currentVal;
}, 0); // 這個0就是初始值
console.log(reduceCount);

遞迴

1.往前走(呼叫自己) 2.有 return 條件 3.邊界條件

範例 10

  1. 階乘 輸入 5 拿到(5!) 5 _ 4 _ 3 _ 2 _ 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// for
function example1(num) {
let n = 1;
for (let i = num; i > 1; i--) {
// 5 5 > 1 5--
// 4 4 > 1 4--
// 3 3 > 1 3--
n *= i;
}
return n;
}
console.log(example1(5));

// recursion
// 遞迴不會有for複雜的邏輯,取而代之是更複雜的邏輯

// 1.往前走(呼叫自己) : example1_re(num - 1)
// 2.有return條件
// 3.邊界條件 : num <= 1

function example1_re(num) {
if (num <= 1) return 1; // 邊界條件
return num * example1_re(num - 1);
}

console.log(example1_re(5));
// 5 * example1_re(4)
// 5 * 4 * example1_re(3)
// 5 * 4 * 3 * example1_re(2)
// 5 * 4 * 3 * 2 * example1_re(1)
// 5 * 4 * 3 * 2 * 1
  1. fibonacci : 前兩個是 1,第三個開始為前兩個和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 使用while迴圈取出fibonacci
function fibonacci(num) {
// 前兩位是1
if (num <= 2) return 1;
let n1 = 1; // 第一位
let n2 = 1; // 第二位
let temp = n1 + n2; // 第三位
// 因為有三位所以只要算到n-2位
// 1->n-2,2->n-1,3->n
// 為了要算到第n-2位,一直--到剩下2
while (num > 2) {
temp = n1 + n2; // 算出下一位(前兩位和)
n1 = n2; // 將第二位當成第一位
n2 = temp; // 將第三位當成第二位
// 一直往後平移
num--;
}
return temp;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//EX: fibonacci(5)
//fibonacci(5) => 1 1 2 3 [5]
// n1 n2 temp (迴圈第一次)
// n1 n2 temp (迴圈第二次)
// n1 n2 temp (迴圈第三次)
// 第一段判斷
if (5 <= 2) return 1; // 5不小於等於2繼續往下
// 初始化資料
let n1 = 1; // 第一位
let n2 = 1; // 第二位
let temp = n1 + n2; // 第三位
//進入迴圈時
//第一次
while (5 > 2) {
temp = n1 + n2; // (1+1 = 2)
n1 = n2; //(1)
n2 = temp; // (2)
num--; // num = 5-1
}
//第二次
while (4 > 2) {
temp = temp + n1; // (1+2=3)
n1 = n2; //(2)
n2 = temp; // (3)
num--; // num = 4-1
}
//第三次
while (3 > 2) {
temp = temp + n1; // (2+3=5)
n1 = n2; //(3)
n2 = temp; // (5)
num--; // num = 3-1
}
//第四次
while (2 > 2) {
// 條件不成立跳出迴圈
temp = temp + n1;
n1 = n2;
n2 = temp;
num--;
}

return temp; // 5