竹白的 JS 學徒特訓班筆記 - 目錄
記錄六角學院所開的 JS 學徒特訓班,為期 60天的特訓。
第十一關:函式參數再練習
題目連結
劇情略。
11. 問題
題目一:老闆想要隨時扣你的薪水
老闆:「今天是發薪日,先發給你薪資 23500 元(遞給小杰」
老闆:「以下三步驟動作請寫成程式」
老闆:「步驟一:昨天你上廁所太久了,我要扣你 1000 元」
老闆:「步驟二:小黑說不喜歡你煮的狗食,我要再扣你 3500 元 (再次取走」
老闆:「步驟三:我今天心情不太好,扣個 500 元意思一下」
小杰:「屁啦!心情不太好關我啥事!」
老闆:「這不是重點,快點算!將之前的寫法換成函式,並增加一個參數,讓我方便何時扣你多少都沒問題」
老闆:「最後你寫的函式,要執行三次,每次都要回報你的總薪水剩下多少。」
1
2
3
4
5
|
var salary = 23500;
//請依照上面的武功秘笈 Codepen,依序實現兩步驟,算出小杰被扣了多少錢
console.log('小杰目前還剩下' + salary + '元');
|
題目二: if + 指派運算子
老闆:「好了,現在我要告訴你贈品條件!」
- 目前小杰手上有 3 個贈品
- 消費滿 100 元就送對方贈品
下圖為第八關截圖,請依照以下邏輯進行改寫:
- 現在來了三個客人,並依序有消費,A顧客消費 150、B 顧客消費 99、C 顧客消費 110。
- 請設計一個函式,裡面代入一個參數為顧客消費金額,確認該客戶是否符合贈品條件,若符合就讓
giftNum
變數減少數量。
- 並依序執行三次函式,每次函式皆會 return 目前贈品數量剩下多少。
1
2
3
4
5
6
7
8
9
|
var giftNum = 3; // 贈品數量
var customerA = 150; // 顧客 A 消費金額
var customerB = 99; // 顧客 B 消費金額
var customerC = 99; // 顧客 C 消費金額
if (客戶A條件) {}
if (客戶B條件) {}
console.log('目前贈品剩下' + giftNum + '個');
|
題目三:if + 指派運算子
老闆:「我現在補齊給你總計 200 個贈品!」
老闆:「然後我覺得現在贈品門檻太高了,我決定大放送,只要滿 50 元就送一個!以此類推,他買 500 元就送 10 個贈品!」
小杰:「老闆你竟然利用我的特休,我跟你沒完啦。」
老闆:「別廢話,客人來了快點!他買完後告訴我贈品還夠不夠!」
下圖為第八關截圖,giftNum 已改為 200 份,請依照以下邏輯進行改寫:
- 請用函式改寫,同時來了三組客人,請用你寫的函式連續執行三次,來幫助顧客是否有符合贈品條件。
- 另外每次執行函式時,都必須告訴老闆一次目前贈品數量。
第一組客人:Mary 買了 10 份薯條,10 份漢堡
第二組客人:Bob 買了 1 份薯條
第三組客人:Tim 買了 20 份薯條,15 份漢堡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var giftNum = 200; // 贈品數量
var friesPrice = 30; // 薯條單價
var hamburgerPrice = 50; // 漢堡單價
// 以下是題目
// mary 買了 10 份薯條,10 份漢堡
// 請計算完贈品規則後,善用指派運算子去計算目前剩下的贈品有幾個
// 並用下面的 if 回報給老闆
if (條件式) {
console.log('老闆!贈品還夠!剩下' + giftNum + '個~');
} else {
console.log('老闆贈品賣光啦~');
}
|
11. 參考解答
題目一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function calculate(num) {
salary -= num;
return salary;
}
calculate(1000);
console.log('小杰目前還剩下' + salary + '元');
// '小杰目前還剩下22500元 '
calculate(3500);
console.log('小杰目前還剩下' + salary + '元');
// '小杰目前還剩下19000元'
calculate(500);
console.log('小杰目前還剩下' + salary + '元');
// '小杰目前還剩下18500元'
|
題目二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
function calculate(num) {
if (num >= 100) {
giftNum -= 1;
}
return giftNum;
}
calculate(customerA);
console.log('目前贈品剩下' + giftNum + '個');
// 目前贈品剩下2個
calculate(customerB);
console.log('目前贈品剩下' + giftNum + '個');
// 目前贈品剩下2個
calculate(customerC);
console.log('目前贈品剩下' + giftNum + '個');
// 目前贈品剩下1個
|
題目沒說明,因此這裡不考慮贈品不足(giftNum
變負數)的情況。
題目三:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function calculate(friesNum = 0, hamburgerNum = 0) {
let total = friesPrice * friesNum + hamburgerPrice * hamburgerNum;
giftNum -= Math.floor(total / 50);
if (giftNum > 0) {
console.log('老闆!贈品還夠!剩下' + giftNum + '個~');
} else {
console.log('老闆贈品賣光啦~');
}
}
calculate(10, 10); // 老闆!贈品還夠!剩下184個
calculate(1); // 老闆!贈品還夠!剩下184個
calculate(20, 15); // 老闆!贈品還夠!剩下157個
|
第十二關:DOM 操作
題目連結
劇情略。
12. 題目
- 請觀看此 Codepen 的線索,試圖找到密碼,並在 Slack 上回傳密碼
- 以下 Codepen 的 HTML 與 CSS 面板都壞掉了,你只能編輯 JS 面板,來去尋找線索
12. 參考解答
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
let url = 'https://hexschool.github.io/JSTraining/stage12/';
// 區塊一,路徑放錯了,得用 setAttribute 換 src 屬性,換成 1.png
document.querySelector('.keyItem1 img').setAttribute('src', `${url}1.png`);
// 區塊二,唯一有放對,不需更改
// 區塊三,請用 innerHTML,指定 keyItem3,讓他插入 3.png 圖片
document.querySelector('.keyItem3').innerHTML = `
<div class="keyItem keyItem3">
<img src="${url}3.png" alt="">
</div>`;
// 區塊四,只能用 style 插入 background 4.png
document.querySelector('.keyItem4').style.background = `url("${url}4.png")`;
|
解答 Codepen
教學、延伸知識連結
第十三關:函式+if 判斷
題目連結
劇情略。
13. 問題
以下為 BMI 計算方式:
- BMI 計算為:體重(公斤) / 身高的平方(單位為公尺)
- 例如 150 公分 50 kg = 50/(1.5*1.5) = 22.2 BMI 指數
- BMI 數值狀態如下
- 體重過輕:BMI < 18.5
- 正常:18.5 ≦ BMI < 24
- 過重:24 ≦ BMI < 27
- 輕度肥胖:27 ≦ BMI < 30
- 中度肥胖:30 ≦ BMI < 35
- 重度肥胖:BMI ≧3 5
小杰打開 Code 才發現,裡面的 if 判斷根本都在亂寫,請依照上面的 BMI 狀態來改寫,並還小杰一個清白。
請修改此 Codepen,並將修改結果回傳到 Slack。
1
2
3
4
5
6
7
8
9
10
|
function calculationBMI(height, kg) {
var bmi = kg / (height / 100 * height / 100);
if (bmi > 20) {
return '過胖!但能吃就是福,維持現況也沒什麼不好的~';
} else {
return '你很瘦~ㄕㄡˋ~~';
}
}
console.log(calculationBMI(178, 70));
|
13. 參考解答
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
if (bmi < 18.5) {
return '體重過輕';
}
if (bmi <= 24) {
return '正常';
}
if (bmi <= 27) {
return '過重';
}
if (bmi <= 30) {
return '輕度肥胖';
}
if (bmi <= 35) {
return '中度肥胖';
}
return '重度肥胖';
|
if
裡面已經使用 return
,就不建議使用多餘的 else if
了。
教學、延伸知識連結
第十四關:監聽與函式設計
題目連結
劇情略。
14. 題目
小杰打開網頁後,發現工讀生只把 HTML 標籤寫好,JS 完全沒寫,
因為 HTML 面板已經壞掉了,請直接修改 JS Code,
讓 .total 的顯示數值,可以正常運作。
並在 Slack 上回傳 carbon JS Code 與 Codepen。
BMI 2.0版 Codepen 網址
1
2
3
4
5
6
7
|
<input type="text" class="height" placeholder="請輸入您的身高(公分)">
<input type="text" class="kg" placeholder="請輸入您的體重(公斤)">
<input type="button" class="send" value="計算">
<p class="total">您的 BMI 指數為
<span class="BMI">22</span>,
狀態是 <span class="status">正常</span>
</p>
|
14. 參考解答
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
|
document.querySelector('.send').addEventListener('click', function () {
let heightDom = document.querySelector('.height');
let kgDom = document.querySelector('.kg');
let height = Number(heightDom.value);
let kg = Number(kgDom.value);
let totalDom = document.querySelector('.total');
// 若輸入不合法的值
if (isNaN(height) || isNaN(kg) || height < 1 || kg < 1) {
totalDom.textContent = '請輸入大於 1 的數字';
return;
}
let bmi = Math.floor(kg / (((height / 100) * height) / 100));
let result = bmiResult(bmi);
totalDom.innerHTML = `
您的 BMI 指數為 <span class="BMI">${bmi}</span>,
狀態是 <span class="status">${result}</span>`;
});
function bmiResult(bmi) {
if (bmi < 18.5) {
return '體重過輕';
}
if (bmi <= 24) {
return '正常';
}
if (bmi <= 27) {
return '過重';
}
if (bmi <= 30) {
return '輕度肥胖';
}
if (bmi <= 35) {
return '中度肥胖';
}
return '重度肥胖';
}
|
教學、延伸知識連結
第十五關:物件運用 - 資料與渲染分離
題目連結
劇情略。
15. 問題
以下是護理師改寫小杰的邏輯,程式碼連結
護理師拿了之前工讀生的 Code 改寫,根本沒用小杰的。但可以看得出來,這個 Code 有刻意遺留了些不完整的地方,像是 bmiData
的物件沒有將條件寫完整,頗有想要再次考驗小杰的味道。
請各位將你們的 Code 跟護理師的進行比較,看看差異在哪裡,並透過 Slack 分享自己吸收的結果,並試著依照自己的邏輯寫一遍。
這次 HTML 面板壞掉了,你唯一可以改的面板只有 CSS 與 JS 面板。
15. 參考解答
這裡就不優化了,直接補齊缺的部分。
補齊所有狀態顏色:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
.blue {
color: blue;
}
.green {
color: green;
}
.pink {
color: pink;
}
.orange {
color: orange;
}
.purple {
color: purple;
}
.red {
color: red;
}
|
建議語意化命名 class 名稱,但這裡就依照題目吧。
補齊 BMIData
物件狀態:
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
|
var BMIData = {
overThin: {
statusText: '體重過輕',
class: 'blue',
},
normal: {
statusText: '正常',
class: 'green',
},
overweight: {
statusText: '過重',
class: 'pink',
},
mildObesity: {
statusText: '輕度肥胖',
class: 'orange',
},
moderateObesity: {
statusText: '中度肥胖',
class: 'purple',
},
severeObesity: {
statusText: '重度肥胖',
class: 'red',
},
};
|
補齊 calculationBMI
函式:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if (bmi < 18.5) {
render('overThin', bmi);
} else if (bmi <= 24) {
render('normal', bmi);
} else if (bmi <= 27) {
render('overweight', bmi);
} else if (bmi <= 30) {
render('mildObesity', bmi);
} else if (bmi <= 35) {
render('moderateObesity', bmi);
} else {
render('severeObesity', bmi);
}
|
render
函式加入其他 class 前要先清除所有 class 樣式:
1
|
statusDOM.classList.remove(...statusDOM.classList);
|
解答 CodePen
教學、延伸知識連結
第十六關:forEach 與 HTML 字串累加
題目連結
劇情略。
16. 問題
小杰一時間還不知道怎麼寫,所以先寫了陣列 + forEach 的方式來累加 HTML 字串,再來顯示介面出來。範例程式碼
請你依照這邏輯,試著改寫物件格式,呈現的格式如下程式碼。
設計好物件後,依序 push 五筆資料到陣列裡,最後整理完字串資料,再 innerHTML 到 ul 裡。
這次 HTML 與 CSS 面板都壞了,請改寫 JS 面板。
PS:請拿上面的 Codepen 改寫即可,不需拿前幾關的 code 來整合
<ul>
<li>小杰的身高為 178 公分,體重是 70 公斤,BMI 數據為 20,狀態為正常</li>
<li>小美的身高為 150 公分,體重是 200 公斤,BMI 數據為 38,狀態為超重</li>
</ul>
16. 參考答案:
物件格式改寫,我改一個就好,剩下雷同。
1
2
3
4
5
6
7
|
{
name: '廖洧杰',
height: 178,
kg: 70,
bmi: 22,
status: '正常',
}
|
str
拿出來,避免每次迭代都被重置,並使用字串樣板加入變數。
1
2
3
4
5
6
7
8
9
10
|
var str = '';
data.forEach(function (item) {
var content = `
<li>${item.name}的身高為 ${item.height} 公分,
體重是 ${item.kg} 公斤,
BMI 數據為 ${item.bmi},
狀態為${item.status}<li>`;
str += content;
list.innerHTML = str;
});
|
教學、延伸知識連結
第十七關:innerHTML+forEach
題目連結
劇情略。
17. 問題
明明陣列裡面有五筆資料,但寫出來的程式碼,列表永遠只顯示一筆資料,究竟小杰哪裡觀念有問題呢?一起來幫助小杰吧~
小杰程式碼網址
請思考並在 Slack 回覆:
- str 放 forEach 外頭跟裡面的差異
- innerHTML 放 forEach 外頭跟裡面的差異
- innerHTML 當要寫內容進去時,會不會將裡面內容給覆蓋掉?
17. 參考解答
- 作用域不同,一個是全域,另一個只作用在
forEach
的 callback
函式內。放在外面才會累加結果。
innerHTML
放在外面就不會迭代,只會跑一次。
- 會覆蓋。
教學、延伸知識連結
第十八關:字串相加 innerHTML+ 樣式搭配
題目連結
劇情略。
18. 問題
挑戰者們不要忘了,JS 始終要搭配妳寫好的 CSS 來進行渲染,護理師好像已經看膩了小杰爛到不行的陽春版本,寫了一個 .list2
版本,請依照他的 CSS 樣式邏輯,將 data 陣列裡面的資料,依序渲染到 .list2
裡面的 li
來顯示。
護理師的 Codepen 網址
18. 參考解答
1
2
3
4
5
6
7
8
9
10
11
|
var list2 = document.querySelector('.list2');
var str = '';
data.forEach(function (item) {
var content = `
<li class="list-card">
<h2>${item.name}</h2>
<p>你的身高是${item.height}</p>
</li>`;
str += content;
});
list.innerHTML = str;
|
第十九關:驗收前夕
題目連結
劇情略。
19. 問題
小杰打開師傅的程式碼,才發現這程式碼其實是來自於 Vic 這位工程師的範例程式碼。
雖然跟設計稿有非常大的差異,但從程式邏輯中,慢慢掌握到了一些概念。
請解讀 Vic 的(程式碼),並在 Slack 上回報他以下邏輯是做了什麼事情:
- arrayBMIrecord 的陣列用途是什麼?
- 請描述 calculateBMI 函式做了什麼事情
- 請描述 render 函式做了什麼事情
19. 參考解答
- 儲存處理過的資料。
- 處理資料、將資料丟到
arrayBMIrecord
、並執行 render
函式。
- 渲染
arrayBMIrecord
資料到畫面上。
第二十關:BMI 計算機團戰關卡
題目連結
劇情略。
20. 題目
完成上方 UI 設計稿。
20. 參考解答
教學、延伸知識連結
第二十一關:BMI 追加功能
題目連結
劇情略。
22. 問題
可憐的小杰又被威脅了,原來院長想要統計每次 BMI 測量的總平均值,一起做完這最後的需求,讓小杰順利離開醫院吧!
22. 參考解答
1
|
<span class="js-bmiAverage">0</span>
|
1
2
3
4
5
6
7
8
9
10
|
const bmiAveragea = document.querySelector('.js-bmiAverage');
function render() {
let sum = 0;
arrayBMIrecord.forEach((item) => {
sum += item.bmi;
});
let avg = Math.floor(sum / arrayBMIrecord.length) || 0;
bmiAveragea.textContent = avg;
}
|
CodePen 解答
第二十二關:陣列調整
題目連結
劇情略。
22. 問題
最新的資料放在第一筆,讓最新資料都能排序在最前面,將資料進行反轉。
22. 參考解答
有好幾種做法,渲染時,從後面迭代資料:
1
2
3
4
|
for (let i = arrayBMIrecord.length - 1; i > 0; i -= 1) {
const item = arrayBMIrecord[i];
// ...
}
|
或是先淺拷貝一份資料,並使用 reverse()
反轉陣列,再迭代資料:
1
2
3
4
5
|
let temp = [...arrayBMIrecord].reverse();
temp.forEach(
// ...
);
|
或是添加資料時,使用 unshift()
將最新資料加在最前面:
1
|
arrayBMIrecord.unshift(userRecord);
|
但使用 unshift
效率不佳,因為背後的運作原理會將每個元素往後移動。
CodePen 解答
教學、延伸知識連結
第二十三關:資料格式處理,陣列 unshift
題目連結
劇情略。
23. 問題
小杰一看到題目整個傻眼,裡面用了他從來沒看過的圖表資料,好在老闆在程式碼裡面寫了些註解,讓小杰知道自己不需要懂圖表框架,好好的把資料處理好後,圖表自然就會顯示正常,一起來幫幫小杰吧!
以下是預期希望出現正常的圖表,請改寫此 Codepen,並在 Slack 回傳你的解法:
PS:HTML 與 CSS 面板壞掉了,只能變更 JS 面板
23. 參考解答
1
|
monthMoney.unshift(title);
|