[Hexschool JS60 Training] — 60天 JavaScript 學徒試煉 Day31-60

60天特訓

Introduction & 前言

結束八週切版直播版,接著 六角學院 開了一門關於 JavaScript(下稱JS) 的新課程。

雖然筆者沒有報名參加,但是 六角學院 為了銜接上課程舉辦了為期 60天的 JS 學徒試煉

這篇文章將紀錄 60天的練習,自己也會出一些新的題目,有興趣的朋友們也可以試著解題,或是在下方留言一起討論。

這篇文章將會記錄第 31 天 - 60 天 的練習。


Summary & 摘要

每天早上校長會出一題關於 JS 的題目,這邊將會記錄下來自己的解題過程,自己也可能會提出新的題目,有解出題目答案或是不了解也可以在下方留言一起討論,如果題目出得不好也請各路大神手下留情。


每日題目

Day31

第三十一天六角的題目為:

今天為感謝日,必須在 Slack 上觀看一個同學的部落格,並且寫上心得。

第三十一天六角的題目解答為:

雖然之前有碰過 JS 但是其實很多地方沒有很熟悉,真的開始做題目才發現很多地方自己並不是很了解。像是昨日的 C3.js 就很生手,還好同學有寫一篇 提姆寫程式(TimCodingBlog) - JS 筆記 - C3.js 基本認識,這讓我想到之前開始寫部落格的初衷,記錄自己的成長過程,並且幫助其他人,就像六角校長說的「永遠都會有比你弱的人」,可能剛好那個人也正在跟妳找一樣的問題點,一個人的進步肯定會慢過一群人一起進步!

解題關鍵:如同賈伯斯說的「Stay hungry. Stay foolish」。

Day32

第三十二天六角的題目為:

結合之前練習的列表渲染,把三十天的圖表一起渲染到畫面上吧!

第三十二天六角的題目解答為:

解題關鍵:今日也算是複習日!

Day33

第三十三天六角的題目為:

今日需要將之前拿到的 API 改為圓餅圖

第三十三天六角的題目解答為:

解題關鍵:今天一樣照著官方指南手,有些小地方要注意,像是之前用到的 Axis(軸) 這裡就不能用,然後 types 也會變成 type,這就是用套件要注意的地方,必須跟著對方的方式走。而 圓餅圖 也可以加入 onclick()onmouseover()onmouseout()C3.js 真的很強大呀!

Day34

第三十四天六角的題目為:

今日一樣需要將之前拿到的 API 處理後判斷名稱大於六個字及小於的人,然後用圓餅圖表示出來。

第三十四天六角的題目解答為:

解題關鍵:因為名稱會有 中文英文,這邊有兩種方法,一種為使用 String.prototype.charCodeAt(),參考文章為 https://blog.csdn.net/qq_43437571/article/details/106088271,判斷字元是否超過 255,缺點為需要跑迴圈每個字拆開;另外有種方法比較簡單,為 正則表達式,不需要拆開判斷,只需要用 replace 即可,參考文章為 判斷中英文字串的長度,方法如下註1

註1

判斷中英文方法為下:

1
2
3
function getlengthb(str){
return str.replace(/[^\x00-\xff]/g,"**").length;
}

Day35

第三十五天六角的題目為:

今日需要將之前拿到的 API 處理之後帶入圖表之中。

1
2
3
4
5
6
<div id="chart"></div>
<div id="chart2"></div>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.18/c3.min.css" integrity="sha512-cznfNokevSG7QPA5dZepud8taylLdvgr0lDqw/FEZIhluFsSwyvS81CMnRdrNSKwbsmc43LtRd2/WMQV+Z85AQ==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js" integrity="sha512-FHsFVKQ/T1KWJDGSbrUhTJyS1ph3eRrxI228ND0EGaEp6v4a/vGwPWd3Dtd/+9cI7ccofZvl/wulICEurHN1pg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.18/c3.min.js" integrity="sha512-bW79RVtvrrTS2QzmDsJeh62Nt4b/RjYlYvi2iEmkXPhzzbXMx69JT/zHgiGcL1Tk5nkLMTF6xkEUuynTkdC9PQ==" crossorigin="anonymous"></script>
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
var chart = c3.generate({
bindto: '#chart',
data: {
// iris data from R
columns: [
['完課率0~20%', 70],
['完課率21~49%', 50],
['完課率50%以上', 30],
],
type : 'pie',

}
});

var chart2 = c3.generate({
bindto: '#chart2',
data: {
columns: [
['完課率0~20%', 70],
['完課率21~49%', 50],
['完課率50%以上', 50],
],
type: 'bar'
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
// or
//width: 100 // this makes bar width 100px
}
});

第三十五天六角的題目解答為:

解題關鍵:這邊一樣取得 API 之後跑迴圈處理資料,在帶入圖表之中。

Day36

第三十六天六角的題目為:

今日必須將原本第 Day-20 的內容改為字串模板,如果原本就已經使用的話就找一樣 ES6 沒學過或用過的東西來學習。

第三十六天六角的題目解答為:

這次學習的為 fetch,以前都是使用 axios 直接打 API,但沒想到 ES6 提供了這個方法,但其實這個用法還是有缺點的,比如說會把 400、500 都當成成功的請求,沒辦法監測請求的進度,但原生的 XHR 是可以的。

解題關鍵:ES6 雖然語法糖很多,但其實實際瞭解又是另一回事,實際能用的上又再度是另一回事,不管 ES6 ES7 ES8 都是要不段的精益求精。

Day37

第三十七天六角的題目為:

在往後將會更多的使用 letconst,並且盡少使用 var,今天將會複習一下關於這三個的差異。

第三十七天六角的題目解答為:

其實剛學 JS 的時候,就有朋友丟 ES6 給我看過,想當然自己當初是超級小菜雞,根本什麼都不懂,所以又過了一陣子(經過六角勇者地下城的洗禮)才又回來摸一下 ES6。這時候對 JS 已經有一些概念了,所以有些地方就明白為什麼不用 var

ES6 之前其實 JS 並沒有 區塊(Block) 的概念,所以常常會有全域變數被污染的事情發生,比方說下面例子:

1
2
3
4
5
6
7
8
var name = '王小明';

// ...掠過千百行 JS

{
var name = '王大錘';
}
console.log(name); // '王大錘'

雖然 var 會被全域污染,但要記得 varfunction 的區域也是一層一層的(function scope),下面再畫一張圖好理解:

關於 var 的奧秘

圖上可以很清楚看到有 三個紅色的 varvarfunction 的區域也是一層一層的(function scope),所以三個 console.log() 分別為 1.王大錘 2.王小明 3.陳小王

上述舉了一個簡單的例子,可能剛開始我們定義好 全域變數,但在我們寫了幾百幾千行 JS 之後可能早已經忘了取過什麼變數了(沒有使用 前端開發工具前端框架 的情況下單支 JS 都會露露長),然後可能中途某個 function 你就這麼剛好的重複使用了這個變數,這時候全域變數就會被污染。

然而 ES6let 出現拯救了這個問題(雖然同時也會有缺點,後面會提到),let 屬於 **區塊(Block)**,它並不會依附在 window 上,所以下述情況會發生:

1
2
3
4
var name_one = '王小明';
console.log(name_one); // '王小明'
let name_two = '王大錘';
console.log(name_two); // undefined

再來 const 比較簡單,和 let 一樣都是屬於區塊內宣告,不會污染到全域,但 const 最大的用處就是在你只能宣告一次,然後不能更改裡面得值,這個會常用在 const api_url = 'https://xxx/xxx/'const win_score = '60'…等等,一旦宣告後面不能再改變,嘗試複寫會出現 **Uncaught TypeError: Assignment to constant variable.**。

最後的最後要來提一下 letconst 的缺點,這個缺點可是讓我吃了幾次虧…就是 舊手機不支援 啦!但還好透過 Gulp 或是 Babel 編譯後可以拯救,如果你不知道怎麼拯救,可以看這篇文章 [Tool Notes] — 關於Webpack #2 - Babel?,當時也是採了許多次坑,然後開始研究 Babel,亦或是可以參考這篇 [Tool Notes] — 關於Gulp

解題關鍵:子曰:「學而不思則罔,思而不學則殆。」,在每次的採坑每次的學習之後還是需要重複思考下次該如何應對,熟能生巧,是寫程式的不二法門!

Day38

第三十八天六角的題目為:

試著解開 letconst 的相關題目。

  1. 請問下面會出現的 console 是?
1
2
console.log(a); //ReferenceError
let a = 10;

會出現 ReferenceError 而不是 undefined,這邊可以看看這篇文章 我知道你懂 hoisting,可是你了解到多深?

  1. 以下是否會正常執行?若不會,會顯示什麼紅字錯誤?
1
2
let a = 1;
a=3;
1
2
let b = 1;
let b = 2;
1
2
const c = 3;
c=4
  1. 此為熱門面試題目

請問 var、let、const 的區別是?

第三十八天六角的題目解答為:

  1. Uncaught ReferenceError: a is not defined

  2. 會正常執行、不會有紅字錯誤。

  3. 不能正常執行,有重複宣告、會出現 Uncaught SyntaxError: Identifier 'b' has already been declared

  4. 不能正常執行,const 只能宣告一次,並且無法在改值、會出現 Uncaught TypeError: Assignment to constant variable.

解題關鍵:當現今瀏覽器支援度越來越高的時候,盡量棄用 var,如果不知道怎麼分別,記得一個原則,要在最外層 window 宣告的變數,就用 var區塊(Block) 內的就改用 let 避免全域污染,而只會拿來宣告不會改值的,就一定要用 const,避免不知情的狀況下被改值了,以下會有個簡單範例(如範例有誤,還請不吝社指出,感激不盡)。

1
2
3
4
5
6
7
8
9
10
11
12
const name = '一中夜市';
var open_time = '17:00';
var end_time = '24:00';

function storeDetail(store) {
document.getElementById('title').innerHTML = `<span>「${name}」有許多的攤販,營業時間大部分為 ${open_time} - ${end_time}。</span>`;
store.forEach((i, k)=>{
let temp;
temp = `<li>攤販 ${ k + 1 }${i}</li>`
document.getElementById('ul').insertAdjacentHTML('beforeend', temp);
})
}

Day39

第三十九天六角的題目為:

假使你已經會箭頭函式,請分享 箭頭函式(arrow function) 會如何影響到 This

第三十九天六角的題目解答為:

因為之前在上 JS核心篇 有寫到一篇關於 This 的文章,這次趁補充 ES6 箭頭函式(arrow function) 的相關知識回去補足它了。

文章在此處 [JavaScript Notes] — 淺談 JavaScript #4,有興趣也可以參考該系列其他篇章,如有誤還請各位手下留情。

Day40

第四十天六角的題目為:

改寫之前第 Day20Day35 的程式碼,需改為 ES6 寫法。

第四十天六角的題目解答為:

之前已經使用 ES6 寫法,所以這邊就再度複習一次囉。

傳送門:20關35關

Day41

第四十一天六角的題目為:

new Date() 時間處理

第四十一天六角的題目解答為:

我們最常使用的建立時間物件應該就屬 new Date() 莫屬,而裡面也可以帶上參數,像是 new Date(value)

關於時間一文可參考我的第一篇部落格文章 [Hero Of UnderGround 地下城] — 4F World Clock 各國時區

Day42

第四十二天六角的題目為:

請用你學會的語法,取出今日時間,並依序組出以下字串

假設今天時間為 8/5,則需透過 new Date() 處理後,印出以下資料

1
2
3
4
5
// 目前時間是 2020/8/5 14:20 
// 2020/08/05
// 2020-08-05
// 今天是禮拜五
// 今天是八月五日,時間為 14:20

第四十二天六角的題目解答為:

這邊起手式一樣為 new Date() 然後再利用各種 API 去取的時間,但要記得幾個小陷阱,比如 月份會從 0 開始,時間因為地區會有所不同…等等。

善用字串模板可以將小於 10 的分鐘或秒數加上一個 0,會更美觀。

Day43

第四十三天六角的題目為:

學習使用 Github Page

第四十三天六角的題目解答為:

之前專案都是傳 Github 這邊不再贅述。

Day44

第四十四天六角的題目為:

了解 window.location 類別的功能,例如轉址、取得網址參數等等,並分享你學的東西與範例程式碼。

第四十四天六角的題目解答為:

[JavaScript Notes] — 關於 Url 轉址及 取得參數

Day45

Day46

第四十五及四十六天六角的題目為:

45 天題目 - 以下有兩顆按鈕,請使用 JavaScript 語法,操控點擊後,能夠轉址到對應網站去

1
2
<button class="google">連到 Google</button>
<button class="yahoo">連到 Yahoo</button>

46-1 天題目 - 以下有兩顆按鈕,是部落格推薦連結,請抓取 data-id 的值後進行轉址:

點擊 Tom 時,網址為 https://www.hexschool.com/?recommend=tom

點擊 John 時,網址為 https://www.hexschool.com/?recommend=John

1
2
<button class="google_2" data-id="tom">Tom 推薦六角學院</button>
<button class="yahoo_2" data-id="John">John 推薦六角學院</button>

46-2 天題目 - 如果網址規則是https://www.hexschool.com/?recommend="值",該如何取出 recommend 的值?

第四十五天及四十六天六角的題目解答為:

解題關鍵:雖然 Codepen 抓不到網址,還是暫時用 Codepen 練習。四十五天的題目跟四十六天其實很相像,插在一個要另外傳參數,而我們秉持的原則就是會想兩個以上類似的 function 就把他們合再一起。而四十六天第二個題目在前一天的文章有提到 [JavaScript Notes] — 關於 Url 轉址及 取得參數

Day47

Day48

第四十七及四十八天六角的題目為:

使用六角提供的 API 練習 AJAX POST,並且使用三個範例分別為 xmlhttprequest、Fetch、axios,做出 註冊登入 的版面。

第四十七及四十八天六角的題目解答為:

之前打 API 都是使用 axios 居多,趁著這次練習熟悉一下 xmlhttprequest、Fetch

首先為 xmlhttprequest

1
2
3
4
5
6
7
8
9
10
11
12
var xhr = new XMLHttpRequest(); // 起手式為 先新增一個 **xmlhttprequest** 方法 

xhr.open("POST", "https://hexschool-tutorial.herokuapp.com/api/signup", true); // 然後在開啟一個實例

xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); // 接著要設定我們要送什麼個是

xhr.send(`email=${email}&password=${password}`); // 我們要送出什麼

xhr.onload = function () {
// ... 做什麼
console.log(JSON.parse(xhr.responseText)); // 這邊可以在查看一次剛剛宣告的 xhr 可以拿到一些資訊
} // 這邊為傳送結束後要做什麼事情

再來為 Fetch(範例取自 MDN):

這個要簡單可以用簡單的方法,也可以使用自定義的方法去打 API,一般來說最簡單的方法為:

1
2
3
4
5
6
7
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});

上面這個為簡單的 get 傳法,接著如果需要自定義會建議把設定包為一個 function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 先定義方法
function postData(url, data) {
return fetch(url, {
body: JSON.stringify(data), // must match 'Content-Type' header
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, same-origin, *omit
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, *same-origin
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // *client, no-referrer
})
.then(response => response.json()) // 輸出成 json,這樣呼叫那邊就能拿到回傳的資訊
}


// 接著呼叫方法
postData('http://example.com/answer', {answer: 42})
.then(data => console.log(data)) // JSON from `response.json()` call
.catch(error => console.error(error))

這邊要注意,雖然直接使用 fetch 像是上方最後的 postData() 禮最後的 response 可以拿到回傳結果,但是僅能拿到 **Status Code**,你不能知道回傳什麼。

例如這次的作業,回傳雖然 200 是成功,但可能會回傳 該帳號已被註冊,所以必須等 response.json() 之後再去看最後拿到什麼。

解題關鍵:練習裡三種方法都有示範,可以使用看看,不過現在有 axios 這麼方便的東西,其實有機會我們還是該好好了解一下底層的做法是什麼,因為你可能在實務上不太會有機會碰到了。

Day49

Day50

第四十九及五十天六角的題目為:

修改題目的 API 設定,因為沒有帶入 Token 所以無法打成功,這邊需要到 The F2E 申請一組 Token

第四十九及五十天六角的題目解答為:

看到 The F2E 真的好懷念,去年最後一關時車禍了,所以未完賽Q。

這次打 API 需要帶入 Token,因為這次使用 axios 來打 API,所以使用 axios 配置。

1
2
3
axios.defaults.baseURL = 'https://example.com'; // 打 API 網址
axios.defaults.headers.common['Authorization'] = `${token}`; // 塞 從F2E拿到的 Token
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 傳送的格式

其實後端需要檢查什麼,可以再另外在前端這邊塞入,這是一種保護的機制,不會讓別人隨意打 API

Day51

Day52

第五十一天及五十二天六角的題目為:

  • 任務一:這頁面需要使用到 GitHub Pages,並設計兩頁,一頁是 index.html 顯示所有房型,每個房型都會帶 a 連結,連結會帶參數,參數請帶每個房型的 id

  • 任務二:當點擊連結進入到 room.html 後,依照取得的 id 資料,去接 [GET] 單一房型細節,並在該頁顯示該房型細節。例如有無提供各種 room service、訂房紀錄等等。

簡單說就是使用 六角學院&The F2E API 串接,拿取所有房型後,再設計一個頁面可以顯示所點擊房型的詳細資訊。

第五十一天及五十二天六角的題目解答為:

先上 DEMOSource Code

首先這次使用 Gulp 來切頁面,如果還不清楚 Gulp 是蝦咪,可以參考筆者之前這篇 **[Tool Notes] — 關於Gulp**,對於前端開發可以省很多力氣,少做許多要重複做的事情,總之推推推!

接著簡短說一下這次的做法:

  1. 最一開始還是要提醒一下,因為這次的 API 會檢查 Token,所以我們必須拿到可以通過檢查的 Token,然後再將 Token 塞在 Headers 裡面,詳細可參考 **49及50天**。

  2. 第一頁 index.html 先把所有房型拿出來並渲染到畫面,這應該沒有太大問題,和 49及50天 一樣,只是在每一個房型點擊跳頁時,需要帶參數在網址上。

1
2
3
function linkRoomHandler(id) {
window.location = `./room.html?roomId=${id}`;
}

*題外話:最近公司剛好在做 LINE 的案子,有些資訊剛好需要存在使用者這邊,如果不想要一直去拿資料,刷新網頁也還想保留資料,就可以使用 LocalStorage,且情況需求,這次筆者還發現了 LocalStorage 雖然是永久儲存直到使用者手動清除或資料清除才會消失,但是我們可以透過給 LocalStorage 存進時間,讓資料自動刪除,有興趣可參考 localStorage設定過期時間*

  1. 在下一頁剛開始就必須判斷有無帶職進來,這邊因為我們已經確網址帶過來的 Key 會是什麼名稱,所以可以使用下列的函式去判斷有無拿到值:
1
2
3
4
5
6
7
8
9
10
11
12
13
function getUrlVal(val) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for(var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if(pair[0] == val) {
return pair[1];
}
}
return (false);
}

getUrlVal('roomId'); // 沒有東西會回傳 false
  1. 接著就可以拿 roomId 去打 API 拿資料啦!然後就是渲染畫面了。

  2. 因為半夜才能做每日練習,這次小偷懶沒有做預約功能,之後再補上。

題外話:這次作業必須使用 GitHub Page 上傳,如果你有使用打包套件,覺得每次改完都要手動去 Build 什麼的很麻煩,可以參考筆者的這篇文章 [Git Notes] — 快速部署 Vue Cli 靜態資源至 GitHub Pages

Day53

Day60

第五十三天開始到六十天六角的題目為:

完成訂房網站的 API 串接,包含 瀏覽房型、預約功能、查看預約功能

第五十三天開始到六十天六角的題目解答為:

這陣子公司案子太忙一直邊做邊修,原本想手刻日曆,但最後沒時間只好找套件套上。

Source Code

Demo

解題關鍵:這題其實在之前 The F2E 挑戰有做過,不過當時沒有串接 API,這次算是補上串接 API 功能,幾乎都是切版及打 AJAX,時間套件使用
Date Range Picker,有興趣可以參考 [Date Range Picker]日期區間選擇器


Conclusion & 結論

目前會每天依序的練習,如果有解開題目答案或是不了解也可以在下方留言呦!如果題目出得不好也請各路大神手下留情。