昨天介紹了用VSCode執行debug模式,今天要來看debug模式可以做什麼?

回憶

昨天介紹了用VSCode執行debug模式,今天要來看debug模式可以做什麼?

目標

  • debug模式更細部說明
  • 程式在debug模式下觀察程式
  • 基本ES6:變數、內建物件、邏輯、迴圈、條件

VSCode 偵錯(debug) 模式

大部的程式執行環境都可以透過編輯器或整合開發環境 IDE 支援debug模式。 Node.js 支援 debug模式,我們可以使用 VSCode 方便介面的操作,對執行的程式debug。

debug 模式

debug 模式就是可查看程式的執行歷程,進而進行干涉。

debug 模式可以做什麼?

  • 觀察程式執行路徑,下中斷點(breakpoint)、操作Step over/Step in/Step out、看執行函式堆疊
  • 觀察/修改變數的值

準備偵錯模式的遊樂場(Playground)

  1. 建立hello-es6 專案,因為資料夾就是一個專案,所以可以直接把昨天的 hello-nodejs 資料夾拷貝一份再改名為 hello-es6,就完成了。順手改 package.json 內的專案名稱 name
  2. index.js內容改成
    1function fool(a) {
    2    console.log('a is:' + a + ' in fool()');
    3}
    4
    5const a = 1;
    6console.log('a is:' + a);
    7fool(a);
    
  3. 執行debug模式:選 Debug 裡的 Start Debugging 或選好執行 index.js 的執行組態再按綠色箭頭 插圖2.png
  4. 看到執行結果 Screen Shot 2018-10-04 at 8.57.03 AM.png

玩轉 deubg

  1. 在第2, 7行下中斷點 Screen Recording 2018-10-04 at 8.58.32 AM.gif
  2. 執行debug模式,看看發生什麼事? Screen Shot 2018-10-04 at 9.06.39 AM.png 沒錯!程式停下來了、停在第2行~莫慌,我們接下去
  3. 按下 Contiune (往右的箭頭) Screen Recording 2018-10-04 at 9.12.36 AM.gif 按第一下 Contiune,就停在第7行,再按一次才會執行完並印出完整的結果

debug 模式常用功能區塊

第一小節,我們看到 中斷點 可以使程式停在這位置,而 Contiune(往右的箭頭) 繼續執行直到下一個中斷點或執行結束。

接下來,我們來看看常用功能區塊 Screen Shot 2018-10-04 at 9.41.12 AM.png

  1. VARIABLES:變數值 執行時可以存取到的變數和他們的值。你甚至可以連點兩下修改他們,進而影響後續執行。
  2. WATCH:自定義程式表達式(expression) 圖中:a+1 會被執行出結果,常用於查看特定的值,像是物件的屬性值object1.property1。
  3. CALL STACK:函數的執行堆疊(stack) 圖中程式執行到第二行,所以會看到最上面是fool() 2:5,表示現在正在 fool() 函數中,第 行第 個字。你可以點擊第二個 (anonymous function) 會看到是從哪進來的,且會 VARIABLES 是進來前的狀態。
  4. BREAKPOINTS:中斷點的位置 勾勾可以開關它們並保留下它們。
  5. DEBUG CONSOLE:condoel.log() 印出的結果。 condoel.log()印到標準輸出stdout
  6. 程式流程控制儀表板(panel):依次是 Contiune, Step Over, Step In, Step Out, Restart, Stop
    1. Contiune:繼續執行
    2. Step Over:不離開當前執行函數,單步執行到下一行
    3. Step In:單步執行到下一行。若有函數就進入
    4. Step Out:離開當前函數後,停留在下一行
    5. Restart:整個 deubg 重新執行
    6. Stop:終止整個 deubg 模式
  7. EVALUATE EXPRESSION: 執行程式碼片斷 這名字我是從 WebStorm 來的,你可以在這直接寫程式執行。把下面這行貼入按Enter執行
    1function sayHi(a) {
    2  console.log('Hi! a is ' + a + ' in syhHi()');
    3}
    4sayHi(a);
    

你可以多玩玩程式流程控制儀表板和 VARIABLESWATCH 區塊,這對於除錯有莫大的幫助

我發現動態的改值或執行程式碼片斷,可能會導致 VARIABLESWATCH 的值殘留舊值。不過,在我的除錯經驗中,真的很少改值。


ES6 (ECMAScript6) 快速學習

上一章,我們已學會用 VSCode 在 debug 模式下運行,這不僅是用來除錯,還可以拿來習學用的。

ES6 是 ECMAScript6的簡稱,它只是個 規格(specification) ,而 javascript 就是實現他的語言。

然而,ES6 的特性不一定 javascript會實現,更重要是能不能在 Node.js 或瀏覽器使用

我覺得不管在什麼環境,你跑跑看就知道了。好消息是 ES6 常用的語法,大部分的環境都支援了。

變數(Variable):用來存取值的名稱

變數是程式存取值的名稱,例如:

1const a = 1;

這行看來簡單,其實有很多小細節在裡面:

  1. 宣告:程式在執行前要先配置記體憶空間 (實際上,在{. . . }內所有宣告的變數都會在此區塊被執行前一起配置)
  2. 變數範圍/範籌/作用域(Variable Scope):這個變數被修飾為 const ,就是一但賦值後「變數的值」再也不能被修改。Scope 還有:letvarconst
  3. 賦值: = 是賦值符號

基本型別/原始型別 (Primitives):有哪些類型的值?

  1. Boolean - true / false
    1const a = true;
    
  2. Null - “沒有值"的值
    1const a = null;
    
  3. Undefined - 被宣告過的變數,但沒有設定值
    1const a = undefined;
    
  4. Number - 數字,像:整數、浮點數
    1const a = 1;
    2const a = 1.1;
    
  5. String - 字元陣例
    1const a = 'hello';
    
  6. Symbol - 全局執行過程中唯一的值,不可能有一樣的
    1const a = Symbol('foo');
    2const b = Symbol('foo');
    3a === b // false
    
    這是 ES6 才引入,用途見 ES6 In Depth: Symbols,但我們不會用到
  7. 除了上述之外,其它值的都是 Object 型別。

常用的內建物件型別:Object, Array, String, Date, Error

這些怎麼用去 google 都可以查的到,所以我只列出常用的操作,想知道有哪函操作可以查看 Standard built-in objects

假如我打開 Object.keys(),會看到如下: Screen Shot 2018-10-04 at 9.54.56 PM.png 文件中會先給簡述,再來是Demo,也可以立刻執行玩看看,之後才是語法或更詳細的說明。先執行程式看看效果,對於學習是很有幫助的,有興趣的人再去深入查看。

接下來的內容看起來很無聊,也沒有必要學會每個函數、更不用背它們,當要用的時候在上 google 查就好了。儘量保持問問題的想法,像是:

  • Q: 怎麼串連子串陣列?A: ['a', 'b', 'c'].join(',')
  • Q: Java 的字串有 split 方法,那 javascript 有沒有?A: 'a,b,c'.split(',')

這樣學起來有趣多了。

Array

 1// 宣告
 2const words = ['a', 'b', 'c'];
 3
 4// 設定值
 5words[0] = 'd';
 6
 7// 取值
 8console.log(words[0]);
 9
10// 轉換
11words.map(word => words + '->'); // a->b->c->

Object

 1// 宣告
 2const person = {
 3  name: 'May'
 4};
 5
 6// 設定值
 7person.name = 'Billy';
 8
 9// 取值
10console.log(person.name);
11
12// 動態塞key-value
13person.fax = '0000000000'
14console.log(person.fax);
15
16// 取keys
17Object.keys(person);
18
19// 取value
20Object.values(person);

String

 1// 宣告
 2const msg = 'hi!';
 3
 4// 串接 string
 5const msg = msg + ' May.';
 6
 7// 樣版字串(Template literals)
 8const msg2 = `${msg} Bye!`
 9
10// 宣告(含特殊字元)
11const msg3 = "Hi!\nMay"

Date

1// 現在時間
2const now = new Date();

雖然有內建的 Date ,但實務上用 moment 套件比好用。

Error

1// 宣告
2const e = new Error('wrong password');
3
4// 拋出例外(exception)
5throw e;

還有其它像:Promise,我想獨立出來說。

邏輯運算

邏輯運算有 ==, !=, ===, !==, &&, ||

這裡我們需要 ===== 是不同的,直接看例子

1console.log(1 == '1'); // true
2console.log(1 === '1'); // false

javascript 是會 type coercion(會自動的隱式轉型),所以 === 就是不做隱式轉型,型別也要一樣。建議使用 ===, !== 有較強的比較結果,避免隱式轉型造成的不可預測的情況。

迴圈(loop)

 1// 陣列
 2const a = ['a', 'b', 'c'];
 3for (let i = 0; i < a.length; i++) {
 4    console.log(a[i]);
 5}
 6a.forEach(element => {
 7    console.log(element);
 8});
 9for (const element of a) {
10    console.log(element);
11}
12for (const key in a) {
13    console.log(key, a[key]);
14}
15
16// 物件
17const object = {first: 1, second: 2};
18for (const key in object) {
19    console.log(key, object[key]);
20}
21for (const key of Object.keys(object)) {
22    console.log(key, object[key]);
23}
24
25// 另外還有 while loop,可以自己查看看

是不是被 for infor offorEach 弄的很亂阿?可以使用 lodash forEach 統一寫法

1const _ = require('lodash');
2_.forEach([1, 2], (value) => {
3  console.log(value);
4});
5 
6_.forEach({ 'a': 1, 'b': 2 }, (value, key) => {
7  console.log(key);
8});

條件符(condition)

if, switch, ()?X:Y(三元運算ternary operation)

 1const a = '1';
 2if(a === '1') {
 3  console.log('euqal');
 4}
 5
 6switch(a){
 7    case '1':
 8    case '2': {
 9      console.log('a');
10      break;
11    }
12    case '3': {
13      console.log('b');
14      break;
15    }
16    default: {
17      console.log('default');
18      break;
19    }
20}
21
22console.log(a === '1' ? 'equal': 'not equal');

利用 &&|| 可做到類似條件運算,這技巧在渲染react component 很好用,可以少寫判斷程式碼

 1// || 直到有值
 2const a1 = undefined;
 3const b1 = null;
 4const c1 = a1 || b1 || 'default c1';
 5console.log(c1); // default c1
 6
 7const a2 = undefined;
 8const b2 = 'b2';
 9const c2 = a2 || b2|| 'default c2';
10console.log(c2); // b2
11
12// && 前面是 true,才會設後面的值,否則是false
13const a = true;
14const b = a && 'set b';
15const c = !a && 'set c';
16console.log(b, c); // set b, false

關於 javascript 的觀察

  1. 變數宣告不用指明 變數型態, 不用像 C++ int a = 1;,反而 Scope 的修飾更為重要
  2. 特別小心 type coercion, 否則會出現有趣的情況(見What the f*ck JavaScript?),typeof只有少許可能的回傳值,這函數不是真的回傳型態
    1const a = [];
    2console.log(typeof a); // object
    
  3. lodash 也提供方便的查型態函數,但還是有可能有無法預期的結果,使用前一定要測測看 Screen Shot 2018-10-05 at 9.07.11 AM.png

回顧

介紹了VSCode debug 模式和操作,幫助我們學習 javascript 語言。同時,了解到javascript有很多因為 type coercion 產生的好笑的情況。

參考連結