昨天介紹了用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)
- 建立hello-es6 專案,因為資料夾就是一個專案,所以可以直接把昨天的 hello-nodejs 資料夾拷貝一份再改名為 hello-es6,就完成了。順手改 package.json 內的專案名稱 name
- 把
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); - 執行debug模式:選 Debug 裡的 Start Debugging 或選好執行 index.js 的執行組態再按綠色箭頭
- 看到執行結果
玩轉 deubg
- 在第2, 7行下中斷點
- 執行debug模式,看看發生什麼事?
沒錯!程式停下來了、停在第2行~莫慌,我們接下去
- 按下 Contiune (往右的箭頭)
按第一下 Contiune,就停在第7行,再按一次才會執行完並印出完整的結果
debug 模式常用功能區塊
第一小節,我們看到 中斷點 可以使程式停在這位置,而 Contiune(往右的箭頭) 繼續執行直到下一個中斷點或執行結束。
接下來,我們來看看常用功能區塊
- VARIABLES:變數值 執行時可以存取到的變數和他們的值。你甚至可以連點兩下修改他們,進而影響後續執行。
- WATCH:自定義程式表達式(expression)
圖中:
a+1會被執行出結果,常用於查看特定的值,像是物件的屬性值object1.property1。 - CALL STACK:函數的執行堆疊(stack)
圖中程式執行到第二行,所以會看到最上面是
fool() 2:5,表示現在正在fool()函數中,第二行第五個字。你可以點擊第二個(anonymous function)會看到是從哪進來的,且會 VARIABLES 是進來前的狀態。 - BREAKPOINTS:中斷點的位置 勾勾可以開關它們並保留下它們。
- DEBUG CONSOLE:condoel.log() 印出的結果。 condoel.log()印到標準輸出stdout
- 程式流程控制儀表板(panel):依次是 Contiune, Step Over, Step In, Step Out, Restart, Stop
- Contiune:繼續執行
- Step Over:不離開當前執行函數,單步執行到下一行
- Step In:單步執行到下一行。若有函數就進入
- Step Out:離開當前函數後,停留在下一行
- Restart:整個 deubg 重新執行
- Stop:終止整個 deubg 模式
- EVALUATE EXPRESSION: 執行程式碼片斷
這名字我是從 WebStorm 來的,你可以在這直接寫程式執行。把下面這行貼入按Enter執行
1function sayHi(a) { 2 console.log('Hi! a is ' + a + ' in syhHi()'); 3} 4sayHi(a);
你可以多玩玩程式流程控制儀表板和
VARIABLES和WATCH區塊,這對於除錯有莫大的幫助
我發現動態的改值或執行程式碼片斷,可能會導致
VARIABLES和WATCH的值殘留舊值。不過,在我的除錯經驗中,真的很少改值。
ES6 (ECMAScript6) 快速學習
上一章,我們已學會用 VSCode 在 debug 模式下運行,這不僅是用來除錯,還可以拿來習學用的。
ES6 是 ECMAScript6的簡稱,它只是個 規格(specification) ,而 javascript 就是實現他的語言。
然而,ES6 的特性不一定 javascript會實現,更重要是能不能在 Node.js 或瀏覽器使用
- Node.js 可以見官方文件ECMAScript 2015 (ES6) and beyond
- 瀏覽器就有點麻煩了,有瀏覽器要怎麼查?可以用Can I use?查網頁技術的支援程度
我覺得不管在什麼環境,你跑跑看就知道了。好消息是 ES6 常用的語法,大部分的環境都支援了。
變數(Variable):用來存取值的名稱
變數是程式存取值的名稱,例如:
1const a = 1;
這行看來簡單,其實有很多小細節在裡面:
- 宣告:程式在執行前要先配置記體憶空間 (實際上,在
{. . . }內所有宣告的變數都會在此區塊被執行前一起配置) - 變數範圍/範籌/作用域(Variable Scope):這個變數被修飾為
const,就是一但賦值後「變數的值」再也不能被修改。Scope 還有:let、var、const。 - 賦值:
=是賦值符號
基本型別/原始型別 (Primitives):有哪些類型的值?
- Boolean - true / false
1const a = true; - Null - “沒有值"的值
1const a = null; - Undefined - 被宣告過的變數,但沒有設定值
1const a = undefined; - Number - 數字,像:整數、浮點數
1const a = 1; 2const a = 1.1; - String - 字元陣例
1const a = 'hello'; - Symbol - 全局執行過程中唯一的值,不可能有一樣的
這是 ES6 才引入,用途見 ES6 In Depth: Symbols,但我們不會用到
1const a = Symbol('foo'); 2const b = Symbol('foo'); 3a === b // false - 除了上述之外,其它值的都是
Object型別。
常用的內建物件型別:Object, Array, String, Date, Error
這些怎麼用去 google 都可以查的到,所以我只列出常用的操作,想知道有哪函操作可以查看 Standard built-in objects。
假如我打開 Object.keys(),會看到如下:
接下來的內容看起來很無聊,也沒有必要學會每個函數、更不用背它們,當要用的時候在上 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 in、for of、forEach 弄的很亂阿?可以使用 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 的觀察
- 變數宣告不用指明 變數型態, 不用像 C++
int a = 1;,反而 Scope 的修飾更為重要 - 特別小心 type coercion, 否則會出現有趣的情況(見What the f*ck JavaScript?),
typeof只有少許可能的回傳值,這函數不是真的回傳型態1const a = []; 2console.log(typeof a); // object - lodash 也提供方便的查型態函數,但還是有可能有無法預期的結果,使用前一定要測測看
回顧
介紹了VSCode debug 模式和操作,幫助我們學習 javascript 語言。同時,了解到javascript有很多因為 type coercion 產生的好笑的情況。
評論