Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

JavaScript 快速複習 2017Q1

2.208 Aufrufe

Veröffentlicht am

1. 宣告式編程
2. 點來點去的鏈式調用如 [].map().filter().sort()
3. ECMAScript 6 和 7 新出現的語法(只講常用)
4. 非同步的基本概念複習
5. callback、ES6 Promise、async/await 之間的關係

Veröffentlicht in: Technologie
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

JavaScript 快速複習 2017Q1

  1. 1. JavaScript 快速複習 2017Q1 by Aysh Su 2017/02/08
  2. 2. 講這堂的目的在哪? 看看現在一堆新東西在解決什麼問題 認識新語法 看新一點的教學都不太可避免看到新語法orz 不要去記,看過有印象看久就習慣 好用的話就記下來用
  3. 3. 今天的主題們 1. 宣告式編程 2. 點來點去的鏈式調用如[].map(). lter().sort() 3. ECMAScript 6 和7 新出現的語法(只講常用) 4. 非同步的基本概念複習 5. callback、ES6 Promise、async/await 之間的關係
  4. 4. 主題一:宣告式編程是什麼? 可以吃嗎^o^
  5. 5. 先看看傳統的命令式編程 你想把所有陣列元素乘以2,指派到新陣列 var arr = [1,2,3]; var arr2 = []; for (var i = 0; i < arr.length; i++) { arr2.push(arr[i] * 2); } console.log(arr2); //[ 2, 4, 6 ] 所謂的「命令」在哪? 要for 要push 要指派變數,全都要一一命令清楚
  6. 6. 太多操作細節 code一長就沒辦法一眼看出在幹嘛
  7. 7. 怎麼改善?
  8. 8. 宣告式編程的解法 var arr = [1, 2, 3]; var arr2 = arr.map(function (value) { return value*2;}); // with ES6 // let arr2 = arr.map(value => value * 2); console.log(arr2); //[ 2, 4, 6 ] 登愣!完全沒有命令  只有宣告要對陣列中所有元素做什麼處理 底層怎麼for 怎麼push ?不重要
  9. 9. 讓程式碼只表達你的目的 將不重要的操作細節隱藏
  10. 10. 常用的內建宣告式編程方法 [].map() 回傳依函數轉換過的元素的新陣列 []. lter() 回傳將原陣列篩選過的新陣列 [].sort() 將原陣列按指定規則做排序 [].reduce() 將所有陣列元素合併成單一個值
  11. 11. 文件去哪查? 假設我要查 [].map() 怎麼用: 1. .map() 是[] 陣列(Array)類型物件的方法 2. 記住: MDN 好棒棒 JavaScript 最方便參考資源沒有之一 3. Google 搜尋「MDN array map」 或「MDN Array.prototype.map」
  12. 12. 跟 HTML DOM 互動也可以
  13. 13. jQuery 或原生的命令式編程 <div> <input type="text" id="todo-input"> <button id="new-todo">Submit</button> <ul id="todo-list"></ul> </div> <script> $('#new-todo').click(function () { var newTodo = $('#todo-input').val(); $('#todo-list').append('<li>' + newTodo+ '</li>'); $('#todo-input').val(''); }); </script>
  14. 14. 問題在哪? 操作誰都要有清楚的 selector 加id 很常見 HTML 跟JS 嵌合太緊密 HTML 版型一改,selector 要重寫的機率很高 怎麼操作也都要個別講清楚 明明做的事情都差不多 人生浪費在'<li>' + value + '</li>' 之上
  15. 15. 宣告式編程帶來什麼不同? h ps://goo.gl/dwyQQE 以 Vue.js 為例
  16. 16. 宣告式編程: HTML部份 <div id="app"> <input type="text" v-model="todoInput"> <button v-on:click="newTodo()">Submit</button> <ul> <li v-for="todo in todos">{{ todo }}</li> </ul> </div> Vue.js 的 v- 來 v- 去在幹嘛? 幫你全自動同步 <input> 的內容到JS 裏的變數 定義 <li> 的數量和內容是按照哪個JS 變數
  17. 17. 宣告式編程: 只操作資料的 JS var app = new Vue({ el: '#app', data: { todoInput: '', todos: [] }, methods: { newTodo: function () { this.todos.push(this.todoInput); this.todoInput = ''; } }); 完全不用寫任何操作DOM 元素的細節!
  18. 18. 主題二:怎麼理解鏈式調用? 點來點去點點點
  19. 19. 沒有鏈式調用的時候 挑戰你的想像力:幫各種暫存變數想名字 var arr = [1, 3, 5, 4, 2]; var tempArr1 = arr.map(function (value) { return value * 2; } ); var tempArr2 = tempArr1.filter(function (value) { return value > var tempArr3 = tempArr2.sort(function (a, b) { return a - b; }); var arr2 = tempArr3; 有沒有更簡潔的寫法?
  20. 20. [].map().filter().sort() 這在幹嘛囧rz? 要訣:從左到右一個一個解讀
  21. 21. 鏈式調用(chaining)例子 var arr = [1, 3, 5, 4, 2]; var arr2 = arr .map(function (value) { return value * 2; } ) .filter(function (value) { return value > 5; }) .sort(function (a, b) { return a - b; }); 1. 算出arr.map() 的結果 2. 拿去. lter() 3. 再拿去.sort()
  22. 22. 鏈式調用(chaining)例子 var arr = [1, 3, 5, 4, 2]; var arr2 = arr .map(function (value) { return value * 2; } ) .filter(function (value) { return value > 5; }) .sort(function (a, b) { return a - b; }); 1. 算出arr.map() 的結果// [2, 6, 10, 8, 4] 2. 拿去. lter() 3. 再拿去.sort()
  23. 23. 鏈式調用(chaining)例子 var arr = [1, 3, 5, 4, 2]; var arr2 = [2, 6, 10, 8, 4] .filter(function (value) { return value > 5; }) .sort(function (a, b) { return a - b; }); 1. 算出arr.map() 的結果// [2, 6, 10, 8, 4] 2. 拿去. lter() // [6, 10, 8] 3. 再拿去.sort()
  24. 24. 鏈式調用(chaining)例子 var arr = [1, 3, 5, 4, 2]; var arr2 = [6, 10, 8] .sort(function (a, b) { return a - b; }); 1. 算出arr.map() 的結果// [2, 6, 10, 8, 4] 2. 拿去. lter() // [6, 10, 8] 3. 再拿去.sort() // [6, 8, 10]
  25. 25. return 出什麼東西 接下來就可以點什麼
  26. 26. 到底 return 出什麼東西? 1. 查文件 2. console.log() 出來看 3. 開發者工具
  27. 27. 主題三:較常用的 ES6 功能
  28. 28. 什麼是 ES6 JavaScript 是ECMAScript (ES) 的實現 ECMAScript 不斷更新版本,加入新功能和語法糖 連IE9 都可以跑的那個叫ECMAScript 5 (ES5) [].indexOf() 也是ES5 才有! 各家瀏覽器漸漸相容ES6 的新功能
  29. 29. 真的只能學不能寫嗎?相容性 當代環境已支援超過95% 的ES6 功能 Firefox Chrome Safari Node.js 針對舊版瀏覽器,可將ES6 編譯成相容ES5 Babel
  30. 30. ES6 ‐ Block‐Scoped Variable 拿來給你取代var 的 用const 宣告常數 用let 宣告一般變數 const PI = 3.14; // 常數宣告時必須指派值 PI = 3; //注意這裡馬上會拋錯!不能重新指派值給已宣告的常數 let id = 123; let name; // let 跟 var 比較像,宣告時要不要指派值都沒關係。 原則上優先使用 const
  31. 31. ES6 ‐ Block‐Scoped Variable const 和let 的變數域(scope) 只作用到{} 相對於var 是function-scoped // 比較差異,想想為什麼? for (var i = 0; i < 5; i++) { setTimeout(function () {console.log('i = ' + i)}, 0); } for (let j = 0; j < 5; j++) { setTimeout(function () {console.log('j = ' + j)}, 0); } 在for 的() 中的let 的scope 是for 的{}
  32. 32. ES6 ‐ Arrow Func on 長這樣() => {} 可以拿來取代匿名函數function () {} 那個() 和{} 在兩種用法都是一樣用意 setTimeout(function () { console.log('yay') }); setTimeout(() => { console.log('yay') });
  33. 33. ES6 ‐ Arrow Func on 只有一個參數時可省略括弧 只有一行且直接作為return 值時 可省略{} 和return 不寫 [1,2,3].map( (val) => { return val * 2; }); [1,2,3].map( (val) => val * 2 ); [1,2,3].map( val => val * 2 ); 會自動 bind this,要留意 通常比較方便,但偶爾會讓踩到this 的坑
  34. 34. ES6 ‐ 樣板字串 樣板字串是用「反撇」!!不是單引號!! 就是你平常打「~」的那顆鍵,不要壓shift `` 裏面可以用${變數名稱} 存取變數 const name = 'John'; `<li>${name}</li>` === '<li>' + name + '</li>' //true
  35. 35. ES6 ‐ 參數預設值 直接在function 定義的參數名稱後面加= 預設值 // 註: 一樣可在()=>的參數括弧中用此寫法 function hello(name = 'world') { console.log(`Hello ${name}!`); } hello(); // Hello world! 就不用再自己判定unde ned 再另外餵值了
  36. 36. ES6‐ 參數解構 直接拆解參數傳入的物件並指派到同名變數 // 註: 一樣可在()=>的參數括弧中用此寫法 const f = function ({ id }) { console.log(id); }; const obj = { id: 123, name: 'John Doe', }; f(obj); // 123 若寫{ id: idOfObj } 則可把傳入物件的.id 指派給idOfObj
  37. 37. ES6 ‐ 變數解構指派 直接拆解參數傳入的物件並指派到同名變數 const obj = { id: 123, name: 'John Doe', }; const { id, name } = obj; // const id = obj.id; // const name = obj.name; const { id: idOfObj } = obj; // const idOfObj = obj.id; 另參數/變數解構也都可以拆陣列 const [a, b] = [1, 2]; // a === 1 && b === 2
  38. 38. ES6 ‐ import/export 瀏覽器中無法直接使用 需搭配如webpack 等工具編譯 在js 檔中透過export 設定要匯出什麼 在另個js 檔能import 匯入剛才的js 檔內容來使用 模組化 效果同require() 和module.exports
  39. 39. ES6 ‐ 物件方法簡寫 const obj = { method1: function () { // 傳統的的方法宣告 }, method2() { // 效果等同上面那種宣告 }, prop1: 'value' };
  40. 40. ES6 ‐ 物件淺合併 Object.assign(目標物件, 來源物件1, ...) 把來源物件的key 和value 對應複製到目標物件上 一個一個來源依序處理 後來的來源與目標有key 重複時, 由後來的value 覆蓋該key 如果value 是物件,不會遞迴合併 淺合併shallow merge 只合併最外層物件 深合併deep merge 才會把每層物件都合併 沒有原生deep merge
  41. 41. ES6 ‐ 剩餘參數 在function 的參數最後用... 將剩餘參數存成陣列 const f = function (...args) { console.log(args); }; f(1,2,3); // [1, 2, 3]
  42. 42. ES6 ‐ Class 和 extends 只是語法糖,底層跟以前的物件導向效果一樣 建議直接看es6-feature.org ,此處不贅述 http://es6-features.org/#ClassDe nition
  43. 43. 主題四:非同步的處理原理
  44. 44. 簡單來說,什麼是非同步? 只有我一個人可以做正事 可是一個人只有一雙手, 同時間只能做一件事 我做A 做到一半, 可以先把B 委託給別人幫忙, 他做完會提醒我說他做好了, 等我處理完A, 再來處理別人已經幫我處理好的B 的結果
  45. 45. 簡單來說,什麼是非同步? 只有一個JS引擎可以做正事 可是一個JS引擎只有一個執行緒, 同時間只能執行一段程式碼 JS引擎做A 做到一半, 可以先把B 委託給瀏覽器幫忙, 瀏覽器做完會提醒JS引擎說他做好了 等JS引擎處理完A, 再來處理瀏覽器已經幫JS引擎處理好的B 的結果 也就是執行B的callback(B的結果)
  46. 46. 記住: JS引擎永遠只有一個執行緒 就是只有那一雙手
  47. 47. 非同步的三個角色 背景環境(如瀏覽器) 背景環境把程式碼塞入Event Loop 隊列 Event Loop 隊列 Event Loop 會把隊列上第一塊程式碼 推給JS 引擎執行 等JS 引擎執行完才再推下一塊程式碼給JS 引擎 JS 引擎 執行JS 程式碼 可以呼叫背景環境的原生非同步API
  48. 48. 瀏覽器的常用原生非同步 API XMLHttpRequest jQuery 的$.ajax() 底層也是呼叫這個 setTimeout()、setInterval() 等等你就會知道為什麼這兩個時間「不準」
  49. 49. 簡單的非同步例子: console.log(1); $.get(url, function (res) { console.log(2) }); console.log(3); 執行結果一定是: 1 3 2 為什麼?
  50. 50. 簡單的非同步例子: 步驟 1 瀏覽器: 塞程式碼區塊1給隊列 隊列: 從瀏覽器取得程式碼區塊1 ======區塊1 開始====== console.log(1); $.get(url, callback); console.log(3); ======區塊1 結束====== JS引擎: 目前手上沒在做事
  51. 51. 簡單的非同步例子: 步驟 2 瀏覽器: 沒事做 隊列: 把區塊1推給沒在做事的JS引擎 JS引擎: 執行隊列塞進來的區塊1 console.log(1); $.get(url, callback); console.log(3); 執行第1行console.log(1);
  52. 52. 簡單的非同步例子: 步驟 3 瀏覽器: 沒事做 隊列: 無 JS引擎: 執行隊列塞進來的區塊1 console.log(1); $.get(url, callback); console.log(3); 執行到第2行時,JS引擎請瀏覽器幫他做AJAX請求 並請瀏覽器在做好AJAX之後 把呼叫callback的區塊塞回隊列
  53. 53. 簡單的非同步例子: 步驟 4 瀏覽器: 沒事做 隊列: 無 JS引擎: 執行隊列塞進來的區塊1 console.log(1); $.get(url, callback); console.log(3); $.get() 就是「把AJAX請求交給瀏覽器」這件事, 委託完瀏覽器,對JS 引擎就算是做完第2行了。 JS引擎繼續執行第3行console.log(3);
  54. 54. 簡單的非同步例子: 步驟 5 瀏覽器: 剛做完ajax 請求,把程式碼區塊2塞給隊列 隊列: 手上拿到區塊2,可是 JS 引擎還在忙 ======區塊2 開始====== callback(ajaxResponse); ======區塊2 結束====== JS引擎: 還在執行區塊1 console.log(1); $.get(url, callback); console.log(3);
  55. 55. 簡單的非同步例子: 步驟 6 瀏覽器: 沒事做 隊列: 發現JS 引擎沒事做,把隊列上第一個區塊推過去 ======區塊2 開始====== callback(ajaxResponse); ======區塊2 結束====== JS引擎: 跑完了,沒事做
  56. 56. 簡單的非同步例子: 步驟 7 瀏覽器: 沒事做 隊列: JS引擎: 執行區塊2,也就是對callback 的呼叫 callback(ajaxResponse);
  57. 57. 非同步處理: 哪裡有坑? 現在你看得懂這個邏輯錯誤在哪了 var answer; $.ajax(url, function (res) { answer = res; }); console.log(answer); // undefined
  58. 58. 非同步處理: 哪裡有坑? 想想看,幾秒之後才會執行setTimout 的callback function sleepFor(sleepDuration) { var now = new Date().getTime(); while(new Date().getTime() < now + sleepDuration) {} } setTimeout(function () { // 預定1秒後執行 console.log('說好的1秒呢?'); }, 1000); sleepFor(5000); //讓JS引擎執行區塊時卡在while卡滿整整5秒 注意 JS 引擎一定會把手上的程式碼區塊跑到完, Event Loop才會再把隊列上的下個區塊推給 JS 引擎
  59. 59. 主題五:callback, Promise, 和 async/await 間的關係
  60. 60. Callback Hell a.k.a. 龜派氣功 只有callback 時, 唯一確保各非同步區塊執行順序的方法 $.get(url1, (res1) => { const param2 = res1.returnValue; $.get(url2, { param2 }, (res2) => { const param3 = res1.returnValue; $.get(url3, (res3) => { const param4 = res1.returnValue; // ... }); }); });
  61. 61. ES6 Promise 來拯救咧 把callback 深度變淺了!結構清楚不少 fetch(url1) .then((res1) => { const param2 = res1.returnValue; return $.get(url2, { param2 }); }) .then((res2) => { const param3 = res2.returnValue; return $.get(url3, { param3 }); }) .then((res3) => { const param4 = res3.returnValue; return $.get(url4, { param4 }); }) // ...
  62. 62. 怎麼用 Promise 拯救 callback 1. 呼叫會回傳Promise 的方法或library fetch(): 瀏覽器原生的新標準AJAX請求API fetch(url) .then((res)=>res.json()) .then((res)=>console.log(res)); axios 等AJAX library jQuery 3.0 以上也有相容Promise/A+ 標準
  63. 63. 怎麼用 Promise 拯救 callback 2. 用new Promise((resolve, reject)=>{}) 包裝 const p = new Promise((resolve, reject) => { setTimeout(()=> { resolve('yay'); }, 1000); }); p.then((res)=>console.log(res)); // yay 注意當你 new Promise 的同時 該 func on 內容已經開始執行
  64. 64. 用 ES7 async/await 假裝同步 單純Promise 的場合 fetch(url) .then((res)=>res.json()) .then((res) => { console.log(res); }); // 一樣只能在 callback 內存取 Promise 的 resolve 值
  65. 65. 用 ES7 async/await 假裝同步 用async/await 幫Promise 加持 async function f() { const res = await fetch(url).then((res)=>res.json()); console.log(res); } f(); // 把值從 Promise 裏面拔出來,magic!
  66. 66. async/await 語法說明 宣告async function () {} 在async function 裏面, 可以await 一個Promise。 把Promise 的resolve 值直接穿越callback 取出 語法寫起來像傳統的同步操作, 執行上卻一樣是基於Promise 非同步 當然可以IIFE (async () => { })(); async function 本身return 值會被Promise 包裝
  67. 67. Ques ons? 可趁機會提問平常看到但看不懂的JS
  68. 68. 延伸壓泡麵閱讀推薦: You Don't Know JS 中文版:你所不知道的JS 英文版在 GitHub 上可免費閱讀

×