# 面試自我練習題
## css
### img title vs alt
* Img Title:作為圖片標題,用來標示圖片說明文字,當滑鼠移到圖片上就會顯示出來。
* Img Alt:
* 作為圖片替代文字,用來描述圖片內容,當圖片失效時才會顯示,否則圖片正常顯示下,得從網頁原始碼才能看得見。
* 幫助視力障礙者,透過電腦輔助工具,理解圖片內容。
* 幫助搜尋引擎爬蟲理解圖片內容,有助於圖片SEO排名。
### 談談CSS的前綴詞是什麼?為什麼需要使用它們?
CSS前綴詞是添加到CSS屬性前的特定瀏覽器標識,用於支援不同瀏覽器中的實驗性或尚未標準化的屬性。例如,-webkit-是用於WebKit引擎(Chrome、Safari),-moz-是用於Gecko引擎(Firefox)。
### 什麼是Viewport?
參考:https://hsinyu00.wordpress.com/2011/04/05/mobile-web-viewport/
viewport的作用是告訴瀏覽器,目前裝置有多寬(或多高),以便在縮放時有個基準。
width通常設為device-width,用意是適應各家裝置的大小,這樣寫CSS時就能放心的把版面寬度設為100%
### 為什麼需要使用Reset CSS或Normalize.css?
不同的瀏覽器對HTML元素有不同的默認樣式,使用Reset CSS或Normalize.css可以提供一個統一的基礎樣式,以確保在各種瀏覽器上呈現一致的外觀。
### 什麼是CSS Box Model?如何避免Box Model相容性問題?
CSS Box Model定義了元素的大小和佈局,包括內容、內邊距、邊框和外邊距。為了避免相容性問題,應該使用box-sizing: border-box;,以確保指定的寬度和高度包括內邊距和邊框。
### position的值, relative和absolute分別是相對於誰進行定位的?
- relative、absolute、fixed、static、inherit
- static是系統默認值。本身沒有定位屬性。
- inherit是繼承父層數值。
- absolute根據父層元素來做定位,若外層沒有元素,則依據當前瀏覽器畫面,其會脫離正常流向。
- relative是根據相對於其正常位置進行定位,元素本身還是存在在那個位置,並未脫離正常流向。
### RWD的優缺點
- 應該考慮
* 媒體查詢。即指定不同的 CSS 顯示樣式。
* 在 CSS 中將使用百分比而不是絕對值。
- 優點
* 用戶體驗友好,因為它可以適應屏幕上幾乎所有的設備
* 節省響應式網頁設計開發成本,只需要開發3套不同的CSS樣式
* SEO友好單個 URL 中的所有內容: 台式機、平板電腦和智能手機用戶都將使用相同的 URL 查看頁面。這對於社交媒體共享和優化搜索引擎排名更有利。
- 缺點
* 老版本IE瀏覽器兼容性不好
* 減慢加載速度,因為會加載一些不必要的 HTML/CSS
* 開發耗時
* 對版面的影響,響應式網頁設計的流動佈局很難讓設計師很好地控制設計風格。
## What is and why to use the Block Element Modifier (BEM) convention?
- BEM 是什麼?
* 一種創新命名 Class 名稱的設計模式。
* Block 區塊:的 HTML 容器會有一個唯一的 class 名稱,也就是這個區塊的名字。
* Element 元素:Element 為 Block 的一部分並且相依於 Block 的意義,簡單來說就是,如果一個區域不能拿到外部單獨使用,那麼就應該作為一個 Element。
* Modifier 修飾符:Modifier 是定義 Block 和 Element 的外觀、狀態或類型。
- BEM 命名給 CSS 以及 HTML 提供清晰結構,結合命名空間提供更多信息,模組化提高代碼的重用,以達到 CSS 命名語義化、可重用性高、後期維護容易、加載渲染快的要求。
使用 BEM 的命名規則,將會如下:
```
<div class="product">
<div class="menu">
<li class="menu__item menu__item--active"><a href="#"></a></li>
<li class="menu__item"><a href="#"></a></li>
</div>
</div>
```
- 優點
- 語義化,此處的語義化並非 HTML 標籤的語義化,對 SEO 可能也沒有任何意義,但閱讀上非常明瞭,可以直接從 HTML 結構就能看出階層關係。
- 減少選擇器層層嵌套,有利於渲染效率。
- 不像 OOCSS 它並不是為了處理關於 CSS 全部的模組化,反倒是像是命名空間的概念,透過 class 名稱建立各自獨立的 CSS 模組,並且不會互相干擾,一定程度上,避免命名的污染。
- 缺點
- BEM 的一個槽點是,命名方式長而難看,書寫不雅,很多人討厭 BEM 就是因為 HTML 會很醜。但相比 BEM 格式帶來的便利來說,我們應客觀看待。
- 類名與命名空間互相依賴,命名空間名稱需要重新變更所有類名,但可使用 CSS 預處理器改善這個缺點。
## js
### const、let、var => 變數宣告關鍵字
[文章1](https://medium.com/@totoroLiu/javascript-var-let-const-%E5%B7%AE%E7%95%B0-e3d930521230)、[文章2](https://medium.com/coding-girl-life/js-var-let-const-ef9895b4773b)、[文章3](https://w3c.hexschool.com/blog/530adff5)、[文章4](https://www.iware.com.tw/index.php?action=blog-detail&id=458)、[何為變數](https://medium.com/@sun8chi/javascript-%E4%BB%80%E9%BA%BC%E6%98%AF%E8%AE%8A%E6%95%B8-var-let-const-%E8%AE%8A%E6%95%B8%E8%B6%85%E7%B4%9A%E6%AF%94%E4%B8%80%E6%AF%94-3f4bfd6264e9)
- var:
- var為函式作用域(function scope),不會受限在區塊作用域(block scope)內=>區塊語句(if、else、 for、 while等)
- 可能會汙染全域變數
- 可以重複宣告
```javascript=
for(var i=0; i<3; i++){
console.log(i,"Hi");
// 依次出現 0 "Hi"、1 "Hi"、2 "Hi"
}
console.log(i);
// 出現3
```
- let:
- 為區塊作用域(block scope)
- 不會產生全域變數
- 無法在同一層 Block 重複宣告變數
- 宣告後能更改值
- const:
- 常用在一些不能被變更的變數
- 在宣告時變數就必定要指定給值,不然會產生錯誤。
- 具備 let 所有的特性(唯一不同點是宣告後不能更改值)
### this的指向
關鍵:this 決定在於函式如何被呼叫
影響 this 的幾種情境
[影片](https://www.youtube.com/watch?v=8uqUD2F_W74)、[文章](https://chupai.github.io/posts/2008/js_this/)、[範例](https://paper.dropbox.com/doc/1129-JavaScript-this-Closure-7Boanrz9AnAjqqRboh123)
- 純粹的調用(一般的函式呼叫、立即函式 IIFE、閉包、回呼函式、*間接參考*)
- 會指向預設的綁定(default binding),也就是全域物件 window
- 物件的方法調用
- Object
- DOM 物件調用
- Object (監聽函式中的 this 會指向的則是該 DOM 物件)
- 建構式的調用
- Object > 屬於 new 它的物件
- bind, apply, call
- 傳入的物件
- 箭頭函示 >箭頭函數會自動將 this 變數綁定到其定義時所在的物件
- window 或 定義的環境
- 箭頭函示不得當建構式
### 何謂封閉包closure
[文件](https://paper.dropbox.com/doc/1129-JavaScript-this-Closure-7Boanrz9AnAjqqRboh123)
- 簡單來說,就是呼叫函式內的函式,將記憶體封存在內層。
- 像這樣,我們把 count 封裝在 counter() 當中,不但可以讓裡面的 count 不會暴露在 global 環境造成變數衝突,也可以確保內部 count 被修改。
```htmlembedded=
function counter(){
var count = 0;
function innerCounter(){
return ++count;
}
return innerCounter;
}
var countFunc = counter();
console.log( countFunc() ); // 1
console.log( countFunc() ); // 2
console.log( countFunc() ); // 3
```
- 外值得一提的是,過去我們需要新增另一個計數器時,可能會再新增另一個全域變數去儲存另一個 count 的狀態。 而改用閉包的寫法之後,只需要像這樣:
- 此時你就會發現 countFunc 與 countFunc2 分別是「獨立」的計數器實體,彼此不會互相干擾!
```htmlembedded=
function counter(){
var count = 0;
return function(){
return ++count;
}
}
var countFunc = counter();
var countFunc2 = counter();
console.log( countFunc() ); // 1
console.log( countFunc() ); // 2
console.log( countFunc() ); // 3
console.log( countFunc2() ); // 1
console.log( countFunc2() ); // 2
```
- 實例

```htmlembedded=
function callMethod(newMoney) {
var money = newMoney || 1000;
return function (price) {
money = money - price;
return money;
}
}
let updateMyMoney = callMethod(10000000000);
let updateYourMoney = callMethod(1000);
console.log(updateMyMoney(100));
console.log(updateYourMoney(100));
```
### 什麼是Callback函式 (Callback Function)?
[文章](https://matthung0807.blogspot.com/2019/05/javascript-callback-callback-function.html)
- Callback函式,亦稱回呼函式,簡單來說就是「在一支函式執行完後,才要執行的函式」。
```javascript=
var doFirst = function (callback) {
console.log('do first...');
callback(); // <---執行傳入的doLater()
}
/** callback function **/
var doLater = function () {
console.log('do later...')
}
doFirst(doLater);
```
### Event Loop
參考: [pjchender](https://pjchender.dev/javascript/js-event-loop-stack-queue/)、[ExplainThis essential](https://www.explainthis.io/zh-hant/swe/what-is-event-loop)、[ExplainThis example](https://www.explainthis.io/zh-hant/swe/js-event-loop-questions)
**事件循環不存在 JavaScript 本身,而是由 JavaScript 的執行環境 (瀏覽器或 Node.js) 來實現的**
透過事件循環機制,能有效解決 JavaScript 單執行緒的問題,讓耗時操作的異步事件不會阻塞主線程。
執行環境概念(Runtime concepts)

* 堆(Heap):它負責處理動態分配 JavaScript 程式運行期間所需的記憶體,特別是用於管理和存儲物件和變數的記憶體。
* 棧 (Stack):採用後進先出的規則,當函式執行時,會被添加到棧的頂部,當執行完成時,就會從頂部移出,直到棧被清空
* 隊列 (Queue):也是一種數據結構,特性是先進先出 (FIFO)。在 JavaScript 的執行環境中,等待處理的任務會被放在隊列(Queue) 裡面,等待棧 (Stack) 被清空時,會從隊列(Queue)中拿取第一個任務進行處理
* 事件循環 (Event loop):事件循環會不斷地去查看棧(Stack) 是否空出,如果空出就會把隊列 (Queue)中等待的任務放進棧(Stack)中執行
* 堆疊框架(Frame):在程式執行過程中,當函式被呼叫時,系統會在記憶體中建立函式的執行環境也就是堆疊框架,其包含了函式執行所需的參數、區域變數等相關資訊。
#### 事件循環 (Event loop)
* 所有任務都會在主線程上執行,採用先進後出的執序列
* 當遇到異步任務,例如:setTimeout,執行環境會調用相關的 API (例如在瀏覽器上會調用 Web API),當遇到這些項目時,會先交給執行環境處理,處理完後,在回傳待執行的 Callback 任務,並被放置到任務隊列中
* 一旦主線程執行序列的所有任務完成之後,就會讀取任務隊列,並將任務隊列第一個,加到執行序列中運行
* 只要執行序列空了之後,就會讀取任務隊列,不斷重複這個步驟,直到所有任務完成,這個流程就是**事件循環 (Event loop) **
### Event queue (事件佇列)
- JS 是單執行緒,所有同步性的工作,瀏覽器會一個個執行,但遇到非同步的操作就會先放到一個叫做 event queue 的地方,等到瀏覽器目前沒有其他工作,就會到 event queue 看看有沒有還沒執行的任務,再把它拿出來執行。
- 在所有非同步事件如 click、setTimeout、ajax…,都不會立即執行這些行為,而是將這些行為放到 event queue 中,等待事件觸發後再回來執行。
### Event Delegation 事件委派
Event Delegation(事件委派)是一種受惠於 Event Bubbling 而能減少監聽器數目的方法。
實作方法是將 click 事件綁在 parent 上,藉由 Event Bubbling 傳遞給 child,而非直接將事件綁定在 child 上。優點是可減少監聽器的數目,缺點是由於需要判斷哪些 child node 是我們有興趣的項目,而必須多寫一些程式碼做判斷。
```javascript=
<div class="parent">
<div class="child" data-name="a"></div>
<div class="child" data-name="b"></div>
<div class="child" data-name="c"></div>
<div class="subitem" data-name="d"></div>
</div>
$('.parent').on('click', '.child', function(){
console.log($(this).data('name'));
});
```
### setTimeout() 與 setInterval()
[常見考題](https://medium.com/schaoss-blog/%E5%89%8D%E7%AB%AF%E4%B8%89%E5%8D%81-08-js-%E8%AB%8B%E5%AF%AB%E5%87%BA%E9%96%93%E9%9A%94%E4%B8%80%E7%A7%92%E5%8D%B0%E5%87%BA-0-1-2-3-4-%E7%9A%84%E7%A8%8B%E5%BC%8F%E7%A2%BC-6564da4c84c7)
[文件](https://kuro.tw/posts/2019/02/23/%E8%AB%87%E8%AB%87-JavaScript-%E7%9A%84-setTimeout-%E8%88%87-setInterval/)
- setTimeout() 的作用 是在延遲了某段時間 (單位為毫秒) 之後,才去執行「一次」
- setInterval() 則是固定延遲了某段時間之後,才去執行對應的程式碼,然後「不斷循環」
- setTimeout() 只會執行一次就結束,而 setInterval() 則是會在間隔固定的時間不斷重複
- setTimeout() 只會執行一次,所以 clearTimeout() 只會在 setTimeout() 指定的時間未到時才會有效果, 若 setTimeout() 的 callback function 已經被執行,那就等同是多餘的了。
- 程式執行到 clearInterval() 就會取消 setInterval() 了。
- setTimeout() 的時間參數明明已經設定為 0,卻還是最後才執行呢? 這正是因為 JavaScript 是單一執行緒所帶來的特性造成,也就是**非同步**
- setTimeout() 或 setInterval() 做優化,誤差永遠都會存在。
- 建議用 requestAnimationFrame 來取代 setTimeout() 或 setInterval()。 比起傳統的 setTimeout() 或 setInterval() , requestAnimationFrame 的執行效能會好上許多。
### ajax說明與實作
[文件(必看)](https://medium.com/%E9%A6%AC%E6%A0%BC%E8%95%BE%E7%89%B9%E7%9A%84%E5%86%92%E9%9A%AA%E8%80%85%E6%97%A5%E8%AA%8C/js-ajax-%E7%AD%86%E8%A8%98-b9a57976fa60)
- 什麼是 AJAX ?
- AJAX 是「Asynchronous JavaScript and XML」(非同步的 JavaScript 與 XML 技術)的縮寫,簡單說就是網頁不用重新整理,就能即時地透過瀏覽器去跟伺服器溝通,撈出資料。
- XMLHttpRequest 物件 — 跨瀏覽器撈資料
- 使用 XHR 物件可以在自己網頁上讀取遠端的 JSON 資料
- XMLHttpRequest 物件的 open() 方法的第三個參數,true 代表非同步、false 代表同步
- 步驟回顧
1. 建立了一個 XMLHttpRequest 物件
2. 傳送到伺服器要資料
3. 回傳資料到自己的瀏覽器
4. 拿到資料後,增加 onload 事件
5. 在 onload 事件上綁定函式,判斷 HTTP 連線是否正常,是的話將回傳的資料渲染至網頁,否的話畫面顯示資料錯誤
```javascript=
// 選取 DOM
var submit = document.querySelector('.submit');
var email = document.querySelector('.email');
var password = document.querySelector('.password');
// 事件監聽
submit.addEventListener('click', signup);
// 函式
function signup(){
//alert('QQ'); 檢查監聽是否成功
var account = {}; //用來儲存使用者輸入的資訊的物件
account.email = email.value;
account.password = password.value;
//console.log(account); 檢查物件裡面是否有吃到資料
var xhr = new XMLHttpRequest();
xhr.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
// 設定文件格式
xhr.setRequestHeader('Content-type','application/json');
// 將要傳送的物件資料轉為字串型別
var data = JSON.stringify(account);
xhr.send(data);
xhr.onload = function(){
//將回傳的資料轉為物件來作後續運用
var callbackdata = JSON.parse(xhr.responseText);
//console.log(callbackdata); 檢查伺服器回傳的資料
//重頭戲: 註冊成功與否用 alert 呈現,要用到 if else 條件式
var result = callbackdata.success;
if(result){
alert(callbackdata.message);
//console.log(callbackdata.success);
} else {
alert(callbackdata.message);
//console.log(callbackdata.success);
}
}
}
```
- get 與 post 的差異
- get:從瀏覽器發出請求,伺服器會回傳資料(在 responseText 裡面回傳一個物件)。
- post:從瀏覽器發出請求,傳送資料時註明格式,若選擇用表單格式,則傳送資料的內容要仿照表單傳送後的網址*。
- post 內容的格式,一般有兩種:
- 表單輸入格式:content-type application/x-www-form-urlencoded
- JSON 格式:content-type application/json
### 什麼是 axios 又該如何使用
[Ajax 、 JSON 與 axios文件與實作練習](https://ithelp.ithome.com.tw/articles/10243383)
- axios 是一種建立在 Ajax 上的套件
- 用法 : axios.get("url").then(function(參數){要執行什麼});
```javascript=
axios.get('https://api.kcg.gov.tw/api/service/Get/b4dd9c40-9027-4125-8666-06bef1756092')
.then(function(response){
console.log(response.data);
});
```
### foreach、map差異
- forEach()方法不會返回執行結果,而是undefined。也就是說,forEach()會修改原來的數組。而map()方法會得到一個新的數組並返回。
```javascript=
let arr = [1, 2, 3, 4, 5];
arr.forEach((num, index) => { return arr[index] = num * 2; });
// arr = [2, 4, 6, 8, 10]
let doubled = arr.map(num => { return num * 2; });
// doubled = [2, 4, 6, 8, 10]
```
### promise
[文件](https://paper.dropbox.com/doc/59--BFwRtBBe7FeMSb3yvLR57TQUAg-9e5EUPKOvy9IWiPOhLg52)、[影片](https://www.youtube.com/watch?v=QVAWqE-R0Ok)、[文章](https://wcc723.github.io/javascript/2017/12/29/javascript-proimse/)、[較清楚的文章](https://medium.com/@xyz030206/promise-%E4%BB%8B%E7%B4%B9%E8%88%87%E4%BD%BF%E7%94%A8-66605ef56e34)
從語意上理解 promise,就是給予承諾確保事情被執行完畢。這是 ES6 新增的語法,主要是因為有非同步的事件需要被處理,而在先前都是使用 callback 來確保事件執行的順序,造成閱讀與理解上不容易,故才誕生此語法。
promise 有三種狀態 pending、fulfilled、rejected,個別代表 等待、完成、拒絕。
使用方式則是在 promise 內傳入要執行的函式,且依序傳入 resolve, reject 這兩個參數。當函式內部的非同步事件使用 resovle 代表執行完成,若使用 reject 則是失敗。
```typescript!
new Promise( /* executor */ function(resolve, reject) { ... } );
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
promise1.then((value) => {
console.log(value);
// Expected output: "foo"
});
```
### [async/await 是什麼?](https://www.explainthis.io/zh-hant/swe/async-await)
async/await 是一種讓異步(非同步)操作更容易理解和管理的語法。
#### async 語法:
使用 async 關鍵字聲明的函式為異步函式,異步函式會返回一個 Promise 物件,而非直接返回函式執行的結果。<details><summary>async 語法範例 </summary>
```javascript=
// 異步函式
async function f2() {
return "Hello! ExplainThis!";
}
f2(); // 輸出: Promise {<fulfilled>: 'Hello! ExplainThis!'}
```
</details>
#### await 語法:
await 是一個運算子,用於等待一個 Promise 完成或拒絕。它通常與 async 函式一起使用,因為只有**在 async 函式內部**或**模組的頂層**,才能使用 await。
### 原型練
[非常易懂的文章必看](https://maxleebk.com/2020/07/25/prototype/)
[JS基本觀念: 原型鏈(prototype chain)](https://medium.com/@mengchiang000/js%E5%9F%BA%E6%9C%AC%E8%A7%80%E5%BF%B5-%E5%8E%9F%E5%9E%8B%E9%8F%88-prototype-chain-96c742893795)
#### 為何需要原型鏈
在使用函式建構式來建立實例時,可以發現 log 這個 function 也會在實例個別建立,這就造成了相同功能卻佔據了兩份資源的狀況。因此為了解決上面碰到的共享問題,工程師替構造函數加入了原型鏈(prototype)的屬性。所有要共享的屬性與方法,就會被放在原型鏈內。
```typescript!
// 這邊Person就是一個構造函數,表示對象的原型,而javascript利用new + 後面的構造函數就能創造出了一個Person的實例。
//
// constructor
function Person(name, age) {
this.name = name;
this.age = age;
this.log = function () {
console.log(this.name + ', age:' + this.age);
}
}
var personA = new Person('Charles', '30');
var personB = new Person('Jane', 29);
console.log(personA.name); // Charles
console.log(personB.name); // Jane
console.log(personA.log === personB.log) // false
// 使用prototype
Person.prototype.log = function() {
console.log(this.name + ', age:' + this.age);
}
var personA = new Person('Charles', '30');
console.log(personA.__proto__ === Person.prototype) // true
```
#### 原型鏈的運作
在實例中,找不到屬性時,可以透過`__proto__`向原型尋找。
例如在 let today = new Date() 後可以使用 getMonth() 或 getDate() 等方法的原因,這些 methods 實際上是在 Date.prototype 裡。
### class 待學習
[文章](https://medium.com/enjoy-life-enjoy-coding/javascript-es6-%E4%B8%AD%E6%9C%80%E5%AE%B9%E6%98%93%E8%AA%A4%E6%9C%83%E7%9A%84%E8%AA%9E%E6%B3%95%E7%B3%96-class-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95-23e4a4a5e8ed)
### Map 與 object 的差別?
參考:https://www.explainthis.io/zh-hant/swe/map-vs-object
* 原始物件的鍵 (key) 只可以是字串,但 Map 的鍵可以是任何東西
* 原始物件不支援迭代 (iteration),但 Map 物件有
* 原始物件的元素沒有順序性,Map 物件則有順序
* Map 提供許多鍵值對常用的方法,但原始物件沒有
### script tag 加上 async & defer 的功能及差異?
[文章](https://ithelp.ithome.com.tw/articles/10216858)

在 script 加上 async 屬性後,與 defer 相同的是會在背景執行下載,但不同的是當下載完成會馬上暫停 DOM 解析(若尚未解析完的話)(而 defer 則是在DOM 解析完後才執行),並開始執行 JavaScript。也因為下載完成後會立即執行,加上 async 屬性後,就無法保證執行順序了。
### [CSS] Reflow 及 Repaint 是什麼?
[文章](https://ithelp.ithome.com.tw/articles/10217427)
### ES6 特性
1. Let與Const
1. 解構賦值
1. 函數參數默認值 與 展開餘數
1. 箭頭函數
1. Promise
1. class 語法糖
1. ESM 模組化
### what is GC(garbage collection)?
ref: [JavaScript 深入淺出 Garbage Collection 垃圾回收機制](https://shawnlin0201.github.io/JavaScript/JavaScript-Garbage-Collection/)
**為什麼需要 GC?**
主要是為了釋放應用程式中不再使用的資料,這些資料通常會被儲存在記憶體中,一旦不再被引用,就會造成記憶體浪費。
**如何處存記憶體?**
V8 引擎由 stack 和 heap 兩個區域組成,並在其中儲存資料。
* stack 存放一些較為簡單的資料,例如原始數值(如 Number、String 等)以及函數調用的上下文(execution context,例如局部變數、函數的執行環境),還有儲存指向 heap 區域資料的指針。補充: Call Stack:專門用來追蹤函數調用和執行過程的堆疊(屬於 stack 的一部分)。
* heap 用來儲存較為複雜的物件類型(非原始類型、複雜類型)。
**記憶體遺失(Memory leak)**
當存放在 heap 的資料,stack 移除對該 heap 資料的引用,卻無法再訪問這些資料時,就會發生記憶體遺漏。
```
let a = ['大家掰掰,這是我們最後一次見面了。']
a = ['大家好,我其實是另一個陣列'] // Memory leak
```
**垃圾回收機制**
* 參考計數 (Reference Counting) 演算法: 透過計算物件的引用次數,當引用次數為零時,該物件即為垃圾。
* 標記掃除 (Mark-and-Sweep) 演算法: 遍歷所有由全局物件所參考的物件,將可達物件標記為活躍物件,然後清理那些無法達到的物件,即視為垃圾。
理解垃圾回收機制儘量避免這些會成為記憶體垃圾的寫法。
## What are the pros and cons when using the map structure in JavaScript?
- 優點
* Map 物件的 Key 可以是字串或「任何物件」。
* 相對於原始的物件,沒有排序概念;Map 物件中的鍵值對 (Key-Value Pair) 是按照加入的順序排列的。
* 可用 size 屬性追蹤鍵值對的數量。
- 缺點
* 大量建立鍵值對資料時,比原始物件來得慢。
* 程式碼看起來比較冗長。
## Vue
### computed vs. watch
| computed | watch |
| -------- | -------- |
| 偵測到資料變動時,會回傳資料 | 偵測到資料變動時,不會回傳值,只會執行工作 |
| 能偵測多個值的變動(只要該資料是在該computed函式裏和data屬性裏) | 只能偵測一個值 |
| 不能帶入參數 | 能帶入參數,第一個參數是新值,第二個參數是舊值 |
|當元件被創建時(created 生命週期),computed 函式會被建立和執行一次。之後如果依賴沒有更新,就不會重新執行和求值,而是回傳之前緩存起來的值。|比起 computed,可以處理非同步工作。|
### Vuex
[文件](https://ithelp.ithome.com.tw/articles/10214429)
Vuex 在這邊所擔任的角色,是屬於共享狀態管理機制( Shared State Management ),主要的目的是讓你在各種不同的元件中溝通。溝通是個簡單的說法,主要的目的還是用於共享某些資訊,用以達到資訊同步的目的。
* State 狀態儲存的物件,Vuex 使用 單一狀態樹 的方式來存放。
* Getters 取得狀態資料的方法。
* Mutations 更新狀態資料的方法。
* Actions 類似 Mutations,但是 Actions 是呼叫 Mutations,且可支援非同步呼叫。
* Modules 用於分割 Vuex 的區塊。
### What is the virtual DOM? How is it beneficial? [文章](https://cythilya.github.io/2017/03/31/virtual-dom/)
- Virtual DOM 是以 JavaScript 物件模擬特定 DOM 結構而產生的樹狀結構。用途是不直接操作 DOM,而改操作這些物件。待一個段落後,再將這些變更更新回真實的 DOM 上,以期提升效能。
- 操作 DOM 的成本是昂貴的,現今網頁的 DOM Element 數量都頗大,瑣碎頻繁地更新容易成為效能瓶頸。如果不直接操作 DOM,而是將頁面上的 DOM 經 parse/traversal 為 JavaScript 物件暫存在某個地方,對這些物件操作,然後再更新到 DOM 上,想必會比直接操作 DOM 來得快速許多。因此,使用 Virtual DOM 的最大好處就是提升效能 。
### What are the component props?
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
## 網域問題
### 如何解決跨域問題
- 兩種常見,也相對正規的解決方式。
- 「跨來源資源共用(Cross-Origin Resource Sharing,CORS)」
- 透過 伺服器在 HTTP Header 的設定,讓瀏覽器能取得不同來源的資源。
- 伺服器端需要在回應的 Header 加上如 Access-Control-Allow-Origin、Access-Control-Request-Method、Access-Control-Request-Headers 等設定,限制伺服器能接受的來源、使用的方法、可攜帶的 Header 等等。
- 當瀏覽器發送資源請求時,如果是 簡單請求,便會直接送出請求;若不符合前述條件,則會透過預檢(Preflighted)請求先敲敲門,確認可以通過伺服器限制,才會發送正式的請求。
- 允許的方法:GET、HEAD、POST
- Content-Type標頭唯一允許的值為:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- Nginx反向代理跨域
- 例如在自己的開發環境,前後端分離的架構,前後端伺服器分別起在 3000 & 5000 PORT,可以透過這樣的設定:
- 當前端需要發送 API Request 時,可以直接打向 localhost:3000/api/...,這個請求就會被 nginx 攔截,並轉送給後端所在的 localhost:5000;這樣就能簡單的規避掉跨域保護囉。
```
server{
listen 3000;
server_name localhost;
location ^~ /api {
proxy_pass http://localhost:5000;
}
}
```
- 原生ajax解決方法
```html=
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
```
```
<!-- var request = new XMLHttpRequest();
request.open('GET', `https://api.twitch.tv/kraken/games/top?client_id=xxx`, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
console.log(request.responseText);
}
};
request.send(); -->
```
### websocket 與 http 比較
- Websocket協議是基於TCP的一種新的網絡協議。它實現了瀏覽器與伺服器全雙工(full-duplex)通信——允許伺服器主動發送信息給客戶端。
| websocket | http |
| -------- | -------- |
| 持久化協議 | 無狀態協議 |
| 雙向性 | 被動性
| 基於HTTP協議 |
## 觀念
### MVC、MVP、MVVM
[文件1](https://kknews.cc/zh-tw/code/l3n8z59.html),[文件2](https://www.itread01.com/content/1556704804.html),[文件3](https://blog.csdn.net/qq_41497111/article/details/95106747),[文件4](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/652064/),[文件5](https://ithelp.ithome.com.tw/articles/10213157)
- MVC的依賴關係
- Model主要是與業務資料有關。
- View是應用程式資料的視覺化表示。
- Controller管理應用程式中Model和View之間的邏輯和協調。
## REST & RESTful
### REST(「具象狀態傳輸」) 定義
- REST 是一種軟體架構風格(並非標準),目的是幫助不同軟體、程式在網際網路中能夠互相傳遞訊息(就像人們平時使用的文法一樣)。
- HTTP 就是一個符合 REST 架構的實作。但是要記得,REST 是一種風格,所以應用程式使用了 HTTP 連線不保證它就是 REST 架構。
---
若想透過網際網路,跟其他電腦(伺服器)取得資訊,就得使用 HTTP 動詞 "GET",若想要增加資訊,就使用 "POST",若想要更新資訊就使用 "PUT"。到這裡,你已經了解到電腦是如何透過共通的語言,在網際網路上進行溝通。
* GET 讀取資源
* PUT 替換資源
* PATCH 更換資源部分內容
* DELETE 刪除資源
* OPTIONS 回傳該資源所支援的所有 HTTP 請求方法
* CONNECT 將連線請求轉換至 TCP/IP 隧道
* POST 新增資源
---
Router, Routing, Route
在談網路基礎建設時,路由器 (router) 是某種實體設備,負責幫每個資料封包 (packet) 選擇傳輸路徑,扮演類似交通指揮的角色。而「路由器幫資料封包們選擇路徑,引導資料按指定路徑移動」的這個過程,被稱為「routing」。
### Web 開發裡的路由
路由不再是實體設備,而是指 URL 的處理程序。這組處理程序會把 HTTP 動詞、URL、和相關的程式碼連接起來。
舉例來說,如果今天收到一支 HTTP request,格式為 GET http://www.example.com/todos ,路由系統會調度出對應的資源,也就是和「瀏覽全部待辦事項」相關的樣板、邏輯、資料等等。
因為有了路由系統,網站對外開放的網址,不需要對應到實際的專案目錄。
### 什麼是 RESTful
運用 HTTP 來表達語義的路由設計風格稱為 RESTful API。所謂的 API 是應用程式介面 (application programming interface),網址也是一種應用程式的「介面」,故稱為 API。
RESTful 風格的網址設計強調從路由結構就能看出要對什麼資料、進行什麼操作。
總之,RESTful 這種「和 CRUD 對齊」的特性會帶來一些溝通的便利性,客戶端只需要知道可用資源,就能依照約定俗成的邏輯,推測出相關的 API。
#### 優點&缺點
- 優點是因爲他對uri進行了限制,只用於定義資源。這樣看起來比較容易理解。尤其是對簡單的對象的增刪改查,很好理解。
- 缺點是因爲這種限制,導致設計uri變得複雜了(有些特殊的業務要比普通的API需要更多次HTTP請求。)。尤其是複雜的關係,操作,資源集合,硬性套用rest原則設計非常困難。
## 資源
[隨機api(練習專用!!)](https://randomuser.me/)
## 何謂Cookie?Session?Cache?
[文章](https://juejin.cn/post/6951651005826072607)
cookie 存儲於瀏覽器端,而 session 存儲於服務端
1. Cookie
* 主要是 Server 將資訊儲存在 Browser
* 浏览器得到 cookie 后,每次同源的请求的请求 header 都会带上 cookie
3. Session — 與 Cookie 相反,主要是將資訊儲存在 Server,但也需要 Cookie 的幫忙才能實現 Session。這樣可能還是有點抽象,較具體的實現方式:通常是 Cookie 會存取一組 Session 的 id(在 Server 具備唯一性), 然後當 Browser 發出請求時,會夾此 Session id,而Server 會根據這組 id 去拿 Session Data(資訊都存在 Server / DB)。
5. Cache —嚴格來說是 Web Cache。為了增加處理速度跟效率,Server 會將一些 Request 的內容儲存在某個地方,通常這地方稱做為 Cache,之後如果有 Request 想要同樣的內容,就直接傳送給它。
## Describe the difference between a cookie, `sessionStorage` and `localStorage`.
### Cookie
Cookie 是附屬於 HTTP 協定中的功能,它的資料會隨著 HTTP 表頭在用戶端與伺服器之間傳遞,故伺服器也可以存取 Cookie 資料。
資料過期時間:可設定,不會隨著瀏覽器關閉而自動終止。
使用範圍: 不指定路徑時,預設採用目前網頁的路徑,並以路徑劃分存在範圍
Cookie 通常被用來保持使用者的登入狀態
### LocalStorage / SessionStorage
是HTML5提供兩種在客戶端儲存資料的方法,彌補了cookie儲存量小、不適用於大量資料本地儲存的問題。
#### SessionStorage
資料過期時間:而當網頁視窗關閉時資料即被清除,故只適合用於儲存暫時性資料。
使用範圍:在新分頁或新視窗中開啟時,都會建立一個新 SessionStorage 且獨立互不相干涉資料。
#### LocalStorage
資料過期時間:可設定,不會隨著瀏覽器關閉而自動終止。
使用範圍:存在範圍的劃分細度只到主機名稱,不再依路徑區分
### 總結
* cookie會與伺服器傳遞資料,LocalStorage / SessionStorage 不會
* 資料過期時間:cookie可以自行設定,LocalStorage 需手動清除,SessionStorage 關閉當前頁面及清除。
* 使用範圍:皆不同,Cookie 以路徑、SessionStorage以頁面、LocalStorage以domain 劃分存在範圍。
## 跨網站指令碼(XSS)、SQL Injection
[文章](https://medium.com/hannah-lin/%E5%BE%9E%E6%94%BB%E6%93%8A%E8%87%AA%E5%B7%B1%E7%B6%B2%E7%AB%99%E5%AD%B8-xss-cross-site-scripting-%E5%8E%9F%E7%90%86%E7%AF%87-fec3d1864e42)
### XSS 跨站腳本攻擊
網站是由 HTML、Javascript、CSS 所組成,所以只要網站提供給 Users 能 “互動” 的地方,也就是動態可以被變更的區域就有可能暗藏地雷引發資安風險 (常見的互動是利用網址列或 input 改變網頁內容或 HTML Attribute)
### Redirect 攻擊
把你導向一個釣魚網站,例如假的銀行網站,讓你在不知情狀況下輸入帳號密碼,也把帳號密碼送給了駭客
### SQL Injection
SQL 常使用於 database 系統中,因此攻擊者可以透過更改語法邏輯或加入特殊指令的方式,擅自竊取、修改資料。
透過指令碼修改 database 的資料,比如:去竄改 apple 購物網站上 iphone 的售價 0。
### CSRF ( Cross Site Request Forgery ),翻成中文叫做跨站請求偽造
指的是陌生人拿了一張有你桌號的菜單點自己想點的餐之後給老闆這件事( Hacker 用帶著你 cookie 的 Request 送給 web server ),那至於跨站跨在哪裡呢?跨在陌生人在你不知情的情況下把有你桌號的菜單送給了老闆,所以跨過了本該知情的你(送出的人不同,所以送出 Request 的 Domain 註2) 也會不同),CSRF 的本質在於 web server 無條件信任 cookie 而沒有再確認或以其他方式驗證( 等於老闆問也不問無條件相信菜單上的桌號,也不看是誰送的),因此只能保證這個Request 發自某個 User ,卻不能保證請求本身是 User 自願發出的( 等於菜單上的桌號是你的,但不代表這個菜是你點的 )。
## 當你在瀏覽器輸入 URL 會發生什麼事呢?
[文章](https://news.gandi.net/zh-hant/2022/05/what-happens-when-you-enter-a-url-in-your-browser/)
1. 查詢 IP 位址:
域名系統(或稱DNS)是在域名和 IP 位址之間建立對應關係的系統。因此,瀏覽器將 URL 提交給 DNS,而 DNS 又會回覆給瀏覽器含有相應資源的伺服器 IP。
3. 初始連接伺服器
瀏覽器與網路伺服器之間就可以建立連線。此處所建立的第一層連線使用**傳輸控制協議**(即TCP Transmission Control Protocol),該連線主要是指在瀏覽器和網路伺服器之間發送與接收數據。
5. 使用 HTTP 協議
HTTP 是用於**交換網路數據**的網路協議
7. 透過 HTTPS(也就是帶有 TLS/SSL 的 HTTP)連線
HTTPS 只是具備額外加密層的 HTTP 協議,該協議讓伺服器和瀏覽器之間發送與接收的所有數據都無法辨識,也就是除了發送與接收者之外的人都無法看見。
9. 接收網頁內容
## 跨瀏覽器相容性問題
### 什麼是跨瀏覽器相容性問題?
跨瀏覽器相容性問題是指在不同的瀏覽器中(如Chrome、Firefox、Safari、IE等)網頁呈現不一致或有不同的bug,需要額外的工作來確保網站在各種瀏覽器中都能正確運行。
### 你在開發中遇到過哪些跨瀏覽器相容性問題?如何解決的?
開發前台購物網站,發現專案不支援 IE 11,打開畫面一面空白。確認錯誤訊息,之後安裝 react-app-polyfill。browserslist 也新增 ie 11 後就解決了。
還有手機板的時候,測試手機是 iOS 11,不支援 intersection-observable,install intersection-observable,來解決相容性的問題。那時候是使用apple電腦連接手機查看錯誤訊息,才得知。
### 什麼是Polyfills?你在專案中如何使用它們?
Polyfills是用於瀏覽器缺少支援的API的代碼片段。我們可以將這些代碼片段引入到專案中,以填充不同瀏覽器之間的功能差異。舉例來說,babel-polyfill可以用來填充一些ES6+的功能。
## 甚麼是 CORS 跨來源資源共用(Cross-Origin Resource Sharing)
同源政策(Same-Origin Policy): 瀏覽器實行同源政策,這是為了保護使用者的安全。同源政策防止一個網頁中的JavaScript從另一個網域請求資源,以防止潛在的安全風險,如跨網站腳本攻擊(Cross-Site Scripting,XSS)和跨網站請求偽造(Cross-Site Request Forgery,CSRF)。
### 如何繞過 CORS 呢?
* **伺服器端設定:**要在HTTP回應的標頭中包含Access-Control-Allow-Origin,指定允許的來源。
* **使用代理:**在開發環境中,你可以設置一個本地代理伺服器,將請求轉發到目標伺服器,並在代理伺服器上處理CORS問題。
* **使用JSONP:**JSONP是另一種解決CORS問題的方法。不過,它只支援GET請求,並且有一些安全風險,因此不是最推薦的方法。
# React 學習
## 優化效能
1. Dynamic Import 方式 React.lazy & React.Suspense
- React.lazy 接受一個 callback function 當作參數,當首次渲染元件時才會 import 該元件的 bundle。
- 當 Suspense 元件內部的元件渲染完成前,就先渲染 fallback 內的元件。
```javascript=
import React, { lazy, Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
<AnotherComponent />
</Suspense>
</div>
);
}
```
2. Dynamic Import 方式 React Loadable 套件
- loader 屬性是一個函式,會 Dynamic Import 需要的元件,當 Dynamic Import 元件還沒渲染完成前,就先渲染 loading 屬性的元件。
```javascript=
import Loadable from 'react-loadable';
const Loading = () => {
return <div>Loading......</div>
};
const LoadableComponent = Loadable({
loader: () => import('./my-component'),
loading: Loading,
});
export default class App extends React.Component {
render() {
return <LoadableComponent/>;
}
}
```
3. 避免直接新增刪除節點
若是 vue 使用v-show 而非 v-if,react 則是修改css的opacity ,避免畫面 reflow、repaint
4. 避免重新建立函式&物件造成 re-render
- 避免使用匿名函式,因為在每次元件 re-render 時,匿名函式都要被重新分配記憶體位置,行內樣式也是一樣的原理。
- 使用 memo 跟 useCallback 搭配
5. 用 map() 渲染列表時,避免用 map 的 index 當作 key 值
- 如果用 map 的 index 當 key,列表的第一個項目被移除,所有列表項目(可以想成陣列裡面的元素)都往前遞補,原本的第二個項目變成新的第一個項目,項目內容當然會改變導致整個列表重新渲染。
# React
## React 的渲染機制
指的是開發好的程式碼元件如何呈現在螢幕上,這個過程透過以下機制來實現。
渲染過程可分為三個階段:Triggering、Rendering 和 Committing。
- Step 1: Trigger a render
渲染的觸發有兩種情境:
在初次建立元件時,React 會觸發渲染。
當元件的 state 或 props 改變時,React 會再次觸發渲染。
- Step 2: React renders your components
在這一步中,React 會根據根節點來計算元件的虛擬 DOM(Virtual DOM)。
當元件被更新時,React 會從被更新的節點開始,向下計算虛擬 DOM 的新狀態。
- Step 3: React commits changes to the DOM
計算完成虛擬 DOM 後,React 將虛擬 DOM 與真實 DOM 進行比對(這稱為「reconciliation」)。
最終,React 會將虛擬 DOM 的改動更新到真實的 DOM,完成渲染。
# 學習清單
## proxy
[資料](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)