# **Front-end Skill** ## **1.Git flow** 提出不同分支功能以便進行版本管理 ![](https://i.imgur.com/XUhrWGR.png) ![](https://i.imgur.com/gKq4sU0.png) 主要分支:(不會因版本的改動,而刪除掉的分支) master 確定可以上線的版本 develop 開發版本,有任何改動就直接從這裡拉出 feature 新功能分支 release 發布分支 hotfix 緊急修復 ## master 專案初始化時的預設分支 主要任務是記錄與追蹤正式版本釋出的狀態 tag的版本號也會記錄在在此分支的commit上 ## develop 在git flow中被定義為主要開發分支 來源從master的最初提交開始 為所有開發的基礎,由此擴建功能 ## feature `develop>>feature>>develop` 在git flow中被定義為新功能分支 來源從develop開始,有新功能需要開發的時候就開此分支 為develop子項任務分支 由develop開始,develop結束 ![](https://i.imgur.com/W61TiSG.png) > --no-ff 使用 --no-ff 標誌在合併操作中,即使合併可以通過快進模式執行,也始終會創建新的提交對象。這樣可以避免丟失有關功能分支歷史存在的信息,並將共同添加該功能的所有提交分組在一起。 在後一種情況下,從Git歷史記錄中無法看出哪些提交對象共同實現了一個功能,您需要手動閱讀所有日誌信息。在這種情況下,撤銷整個功能(即一組提交)是非常困難的,而如果使用了 --no-ff 標誌,則可以輕鬆完成。 是的,它將創建幾個更多的(空)提交對象,但收益遠大於成本。 > 參考資料 https://medium.com/@fcamel/%E4%BD%95%E6%99%82%E8%A9%B2%E7%94%A8-git-merge-no-ff-d765c3a6bef5 ## release `develop>>release>>master/develop` 在git flow中被定義為發布分支 作為上線前的測試分支,若有問題會在此分之作修改 確認測試無誤後,除了會合併回master,也會合併到develop ![](https://i.imgur.com/wwPkKMV.png) https://nvie.com/posts/a-successful-git-branching-model/ ## hotfix `master>>hotfix>>master/develop` 從master切出,作為緊急修復的分支 熱修分支源於必須立即處理正在運行的生產版本中不希望出現的狀態的需求。當必須立即解決生產版本中的關鍵漏洞時,可以從標記生產版本的主分支上分支出一個熱修分支。 完成後再合併回 master&develop > ### 總結 > master、develop為主要分支,基本上所有分支都是從這兩個切出 > feature是從develop切出,最後回到develop > release是從develop切出,最後回到master&develop > hotfix 從master切出,完成後回到master&develop ## **2.Js** * Scope * Closure ## Scope&closure **語法作用域(scope)** 作用域就是限制某個變量在某個作用域有效 * 全局 (整個文件有效) * 局部 (某個區域有效) **JavaScript 有 9 種作用域:** Global scope Block scope Function scope async (Async function scope) 後面會在講到,在此先不提 ====以上比較常用==== Module scope Script Catch Block With Block Eval generator (Generator function scope) ### Global scope 全域作用域 整個JavaScript代碼中可見的變量,也就是存在於最外層的作用域中,不在任何函數、條件語句或其他區塊作用域中聲明的變量。 使用 var 產生的變數會自動成為 Global Scope ![](https://i.imgur.com/dkduGQH.png) 或是不使用var也會成為 Global Scope ![](https://i.imgur.com/2hW4zyh.png) 全局變量在整個JavaScript代碼中都是可見的,因此它們容易被意外修改 ```javascript= let myVar = 10; function myFunction() { myVar = 20; } myFunction(); console.log(myVar); // 20 ``` myFunction() 函數中修改了全局變量 myVar 的值,導致最終輸出的結果不是我們最初預期的 10,而是 20 ### Block scope 塊級作用域 優點: Block scope可以讓變量的生命週期受限於某個特定的代碼塊,這樣可以避免變量污染全局作用域,同時也可以更好地控制變量的可見性和可訪問性。 if、while、for 等都會形成 Block 作用域,{...}也是 其特性就是函數內部執行完的變量會被銷毀 ```javascript= function myFunction() { let x = 10; console.log(x); // 10,函數執行結束後,變量 x 就會被銷毀 } ``` ```javascript= function myFunction() { if (true) { let x = 10; console.log(x); // 10,函數執行結束後,變量 x 就會被銷毀 } console.log(x); // ReferenceError: x is not defined } ``` ### Function scope 函式作用域 每個函式都會形成一個作用域 函式會建立自己的範疇,其內的識別字(不管是變數、函式)僅能在這個函式裡面使用 在function scope裡 var let const意義都是一樣的 ```javascript= function myFunction() { var x = 1; console.log(x); // 1 } myFunction(); console.log(x); // ReferenceError: x is not defined ``` 變量 x 是在 myFunction() 函數中聲明的局部變量。我們可以在函數內部訪問它,並正常地輸出其值。但是,當我們嘗試在函數外部訪問 x 時,JavaScript 會報錯,提示 x 未定義 > 參考資料 > https://www.cythilya.tw/2018/10/19/function-vs-block-scope/ > 參考資料 > https://blog.51cto.com/u_15506823/5927381 ### 總結 Scope 有兩種,全域與區域 **Global scope** 全域作用域,作用範圍影響到整個程式,要少用 **Block scope** 用if、while、for 等形成 Block 作用域,函數內的變量執行完就會被銷毀 **Function scope** 函式自己會形成一個作用域 ## Hoisting 在 JavaScript 裡面,如果你試圖去對一個還沒宣告的變數取值,會發生以下錯誤: ```javascript= console.log(a) // ReferenceError: a is not defined ``` 會回傳一個a is not defined的錯誤,因為你還沒宣告這個變數,所以 JavaScript 也找不到這變數在哪,自然就會拋出錯誤。 ```javascript= console.log(a) // undefined var a ``` var a 被提升了,因此輸出undefined `*var被提升之後,會被初始化成undefined*` 除了變數宣告以外,function 的宣告也會提升而且優先權比較高,因此下面的程式碼會輸出function而不是undefined。 ```javascript= console.log(a) //[Function: a] var a function a(){} ``` ## Closure 閉包是一種資料結構 包含函式以及記住函式被建立時的當下環境 `假設你在自己的房間裡工作,需要用到客廳裡的一個文件夾,但你不想每次都去拿一次,因為那會很麻煩。那麼你可以在自己的房間裡創一個閉合的包裹(類似於一個文件夾),把需要用到的文件夾放進去,並且把這個包裹交給自己使用。這樣,你就可以在你的房間裡自由地使用這個文件夾,而不必每次都去客廳拿,因為文件夾已經被包含在你的包裹中了。在這個例子中,你的房間就相當於函數,閉包就相當於包裹,文件夾就相當於需要訪問的變量。` ```javascript= function createCounter() { let count = 0; // 外部作用域中的变量 function counter() { count++; // 访问并修改外部作用域中的变量 console.log(count); } return counter; // 返回内部函数 } const myCounter = createCounter(); // 创建一个闭包 myCounter(); // 輸出 1 myCounter(); // 輸出 2 myCounter(); // 輸出 3 ``` ## 3.Node.js 特性 V8 * 單執行緒 * 非阻塞 * 非同步 IO * 事件循環 (event loop) NodeJs -> 單執行緒 ->想要效能好? ->把會阻塞的工作外包給別人 ->怎麼把工作站接過來? ->event loop ->callbackhell ->Promise ## **event loop** 事件迴圈 為何會產生事件迴圈? 因為Js特性一次只能調用一次函式 call stack ```javascript= function multiply(a, b) { return a * b; } function square(n) { return multiply(n, n); } function printSquare(n) { let result = square(n); console.log(result); } printSquare(4); ``` ![](https://i.imgur.com/fx3YeJ0.png) stack: 先進後出(FILO, LIFO),應用: 瀏覽器上的上一頁、函式呼叫 queue: 先進先出(FIFO),應用: 任務排隊 ![](https://i.imgur.com/eAP7B3c.png) ![](https://i.imgur.com/luhEciL.png) > 參考資料 > https://yeefun.github.io/event-loop-in-depth/ ## **Callback** 一個程式執行完再去執行另一個程式 讓函式成為另一個函式的參數 Ex: setTimeout Onclick… ![](https://i.imgur.com/qfkh0Ao.png) 欲成為callback function需如以下寫法 ![](https://i.imgur.com/N59CJn1.png) 為了解決當一遇到函式需要等待,但其他函式又與該等待的函式有關連時,就會使用CallBack Function的時機點來處理。 ![](https://i.imgur.com/OaEVLUk.png) 缺點:callback hell ![](https://i.imgur.com/ztCqty7.jpg) 以下為callback語句,易讀性較差,且難以閱讀 ```jacascript= a(function (resultA) { b(resultA,function (resultB) { c(resultB,function(resultC){ console.log(resultC); }) }) }); ``` 若改寫成以下易讀性較高 ```javascript= a() .then(function (resultA) { b(resultA) }) .then(function (resultB) { c(resultB) }) .then(function (resultC) { console.log(resultC) }) ``` > .then方法 異步執行 ## **Promise** ![](https://i.imgur.com/5HSiQMd.png) 為了解決callback hell ![](https://i.imgur.com/2hPaFUr.png) ```javascript= function a() { return new Promise((resolve, reject) => { resolve(resultA); }); } a() .then(function (resultA) { b(resultA) }) .then(function (resultB) { c(resultB) }) .then(function (resultC) { console.log(resultC) }) .catch(function (erro) { console.log(error); }); ``` Promise hell ```javascript= function a() { return new Promise((resolve, reject) => { resolve(resultA); }); } a() .then(function (resultA) { b(resultA); return resultA; }) .then(function (resultA) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(resultA + 1); }, 1000); }); }) .then(function (resultB) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(c(resultB)); }, 2000); }); }) .then(function (resultC) { console.log(resultC); }) .catch(function (error) { console.log(error); }); ``` ## Async / Await Promise 的語法糖 -> 只要是 promise-based 就可以用 * await 一定要寫在 async 函式裡 * 用來「暫停」函式的,只暫停 async 函式範圍 * 被 await 的這個 promise 物件 resolve 或者 reject 就解除暫停 * 沒有提供錯誤處理機制,只能用 js 內建的 try-catch ```javascript= async function asyncFunc() { try { const resultA = await a(); const resultB = await b(resultA); const resultC = await c(resultB); console.log(resultC); } catch (error) { console.log(error); } } asyncFunc(); ``` 總結 ``` NodeJS 是單執行緒 single thread -> 效能好? -> 把速度慢、會阻塞的工作外包給別人做 -> 怎麼接回工作? -> 當外包公司把事情做完後,會把 callback 函式丟進去 Queue -> event loop 會一直去監看 queue 有沒有工作、stack 裡還有沒有工作 -> 當 stack 是空的時候,event loop 就會把工作(cb)從 queue 搬回 stack 去,讓 single-thread 去執行他 -> callback hell -> promise -> promise hell 或者他很難控制 conditaion -> async/await ```