---
# System prepended metadata

title: JS

---

JS
===

## JS簡介
> - 最初為了解決表單的驗證 (當時網速慢，接送服務器的資料很久)
>   - 模擬網速工具
>     - 這東西可以模擬網速快慢的樣子
>       <img src="https://i.imgur.com/ZqMUVTv.png" style="width: 300px;"/> <img src="https://i.imgur.com/Q3pAMom.png" style="width: 100px;"/>
> - Netscape 為了避免用戶沒有輸入資料就送出而等很久，想在客戶端驗證資料有無輸入而開發了LiveScript
> - 後來與Sun合作，將其改名為JavaScript，以利推廣(Java市佔高)，兩者是不同的東西
>   - Java: 服務器的編程語言
>   - JavaScript: 客戶端的編程語言

## JS組成
> - [ECMAScript](https://zh.wikipedia.org/wiki/ECMAScript)
>   - 一開始有Netscape的JS，後來微軟也寫了一個JScript，造成支援的困擾
>   - [ECMA International](https://zh.wikipedia.org/wiki/Ecma%E5%9B%BD%E9%99%85)(European Computer Manufacturers Association, 歐洲電腦製造商協會) 訂立了一套ECMAScript標準
> - [BOM](https://zh.wikipedia.org/zh-tw/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B)
> - [DOM](https://zh.wikipedia.org/wiki/%E6%96%87%E6%A1%A3%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B)



## 引入方式
### 行內
```htmlmixed=
<body>
    <input type="button" onclick="alert('GodJJ')"/>
</body>
```

### 寫在 \<script> 內
```htmlmixed=
<head>
    <meta charset="utf-8">
    <script>
        alert('5566');
    </script>
</head>
```

### 外嵌
```htmlmixed=
<head>
    <meta charset="utf-8">
    <script src="test.js"></script>
</head>
```
```javascript=
alert('I sad.');
```
> - 引入的標籤內不要再寫JS Code，不會執行


## 變量 (variable)
> - 程序運行中，會把臨時數據存到記憶體中
> - 變量就是記憶體的標示符，根據變量名可以獲取記憶體存儲的數據

### 使用變量

> - 聲明變量並附值
```javascript
var num1 = 3;

console.log(num1); // 就是一般func調用, 暫略解釋
```
```javascript
// js的註釋
var str1 = 'GoGoRo'; // str要用引號框起來, 為了跟css區分(""), 所以常用''

console.log(str1);
```
> - 先聲明，後附值
```javascript
var num1;
num1 = 3;

console.log(num1)
```
> - 同時聲明多個變量並附值
```javascript
var str1 = 'haha', 
    num1 = 5566;

// console.log(str1)
// console.log(num1)
console.log(str1, num1)
```

> - 同時聲明多個變量，後附值
```javascript
var str1, num1
str1 = 'haha'
num1 = 5566

console.log(str1, num1)
```

### 變量命名
> - 規則
>   - 由==字母==, ==數字==, ==_==, ==$== 組成
>     - ```
>       > var num^ = 3
>       < Unexpected token '^'
>       ```
>   - 不能由數字開頭
>     - ```
>       > var 1num = 1
>       < Invalid or unexpected token
>       ```
>   - 不能是保留字, 例如 while, for, class
>     - ```
>       > var while = 1;
>       < Unexpected token 'while'
>       
>       > var for = 1;
>       < Unexpected token 'for'
>       ```
>   - 變量名區分大小寫
>     - ```
>       > var num = 7
>       < undefined
>       
>       > num
>       < 7
>       > Num
>       x Num is not defined at <anonymous>:1:1
>       ```
> - 規範(非硬性)
>   - 駝峰命名
>   - 變量名有意義

## 註釋
> - 單行註釋
>   `// xxx`
> - 多行註釋
>   ```
>   /*
>     xxxxx
>     xxxxx
>   */
>   ```

## JS 數據類型
> - JS屬於弱類型語言, 亦即在source code時不用先定義類型
```javascript=
var num1 = 1; // 書寫時沒有定義類型, 
              // 待CPU執行該語句時, 存儲在記憶體的數據才有類型

// c 語言定義變量，書寫時就要定義類型
  // int num1 = 1 
```

### Number
> - 進制
```javascript=
// 八進制 0~7
   
var num = 010 // undefined
num // 8
// 如果出現超過8的值, 則會忽略0來當成十進制看待
var num = 018 // undefined
num // 18 > 十進制

// 十進制 0~9
var num = 10 // undefined
num // 10

// 十六進制 0~9 A~F
var num = 0xA
undefined
num // 10
```
> - 浮點數
>   - 延伸研究 Keyword: 
>     - IEEE-754
>     - 浮點數轉二進制
```javascript=
// 科學記數法
var i = 1e-2 // undefined // 1*10^-2
num // 0.01
  // ps. 1e+2 = 100 = 1*10^2

// 浮點數誤差
  /*簡單說就是由於浮點數有時候很難很完美的轉二進制, 就好像1/3一樣
    當設置位數上限時(精度)，就會不精確，就好像 0.33不完全等於1/3一樣
    所以浮點數運算時有時會有誤差 */
  // ps. JS 精度為 17 位小數
0.1+0.2 // 0.30000000000000004
1-0.9 // 0.09999999999999998
1-0.7 // 0.30000000000000004
```
> - 特殊數值
```javascript=
// MAX_VALUE : 電腦可以存儲的最大值
  var num = Number.MAX_VALUE // undefined
  num // 1.7976931348623157e+308

// MIN_VALUE
  Number.MIN_VALUE // 5e-324

// Infinity : 無限大
// -Infinity : 無限小
```

> - 數值檢測
    - NaN: Not a number
    - isNaN: is not a number
```javascript=
a = 100 // 100
isNaN(a) // false > a 是否不是一個數字？False

a = 'haha' // "haha"
isNaN(a) // true > a 是否不是一個數字? True
```

### String
`'abc'` `"abc"`
> - 轉譯: \
>   - Q. `print('a'b"c"d'e')`
>     - `'a\'b\"c\"d\'e'`  或 `'a\'b"c"d\'e'`    
> - 轉譯符
>   - `\n` : 換行
>   - `\r` : return
>   - `\t` : tab
>   - `\b` : 空格
>   - `\f` : 換頁
>   - `\"` : "
>   - `\'` : '
>   - `\\` : \
>   - `\xnn`: 以16進制表示ASCII, 例如`\x40` : @
>   - `\unnnn`: 以16進制表示Unicode, 例如`\u0b18` : "ଘ"
> - 字符串長度 length
```javascript=
a = 'godjj'
a.length // 5
```
> - String 拼接
>   `+` 在不同情境有不同作用
```javascript=
// num + num
  3+4 // 7

// str + str
  "haha" + "haha" // "hahahaha"

// num + str
  123 + "haha" // "123haha"
               // 先將num轉成str 再拼接
// Boolean + str
  true + "haha" // "truehaha"
  
// boolean + num
  true + 123 // 124 = 1+123
  false + 123 // 123 = 0+123
```

### Boolean 
> - true = 1/ flase = 0
> - 小寫

### undefined & null
> - null : 空
> - undefined: 沒有賦值
```javascript=
var a = 100 // undefined : 這整句話是沒有賦值的
a // 100 : a 賦值 100
```
### object
> - 我在python學的那些集合類型，在這都是object

```javascript=
a = null
typeof a // "object"

a = [1,2,3]
typeof a // "object"

a = (1,2,3) // 3 : 沒有 tuple
typeof a // "number"

a = {"a":1}
typeof a // "object"
```

### typeof
> 查詢變量類型
```javascript=
a = 100 
typeof a // "number"

a = '100'
typeof a // "string"

a = true
typeof a // "boolean"

var a;
typeof a // "undefined"

a = null
typeof a // "object"
```

## 類型轉換

### 轉成String
> - `var.toString()` 或 `String(var)`
>    - null(object) 跟 undefined 沒有 toString 方法, 只能用 String() 轉
```javascript=
// 不是真的轉換那個變量, 而是把參數丟進去類或函數所返回的值是str

a = 100 // 100

a.toString() // "100"
String(a) // "100"

a // 100
typeof a // "number"
```
```python
# 用python思考看看
In [1]: def String(i): 
   ...:     return str(i)

In [3]: a = 100
In [4]: String(a)                 
Out[4]: '100'
In [5]: a                        
Out[5]: 100
In [9]: type(a)                   
Out[9]: int

# class版本的我還沒想到要怎麼把 a 指向 class num() 
# 我猜 a 是丟到一個函數判斷是什麼類型
# 然後創那個類型的實例類讓a指向, 調用那個類的函數 toString(), 
# 而且實例屬性把a的值存起來 
# 
# class num():
#     def __init__(self, i):
#         self.val = i
#     def toString(self):
#         return str(self.val)
```
> - 拼接str的方式
```javascript=
100 + '' // "100"
null + '' // "null"
undefined + '' // "undefined"
```

### 轉成數字
> - Number(var)
```javascript=
    Number('123') // 123
// Number() 轉換時，如果內容有非數字，就直接返回NaN
    Number('123abc') // NaN
    
// Number() 可以轉換 Boolean
    Number(true) // 1 
    Number(false) // 0
    
// 小數也能轉換
    Number('100.1') // 100.1
    Number('100.1.1') // NaN
```
```python
# 用正則試試看
In [1]: import re 
In [23]: a = '100'
In [24]: b = 'abc100'
In [25]: c = '100abc'  

In [30]: print(re.match(r'\d.+?\d+$', a))
<re.Match object; span=(0, 3), match='100'>
In [31]: print(re.match(r'\d.+?\d+$', b))  
None
In [32]: print(re.match(r'\d.+?\d+$', c)) 
None

In [41]: a = '100.1'
In [42]: b = '100.abc'

In [43]: print(re.match(r'\d.+?\d+$', a))
<re.Match object; span=(0, 5), match='100.1'>
In [44]: print(re.match(r'\d.+?\d+$', b))
None
```

> - parseInt(var)
```javascript=
    parseInt('123') // 123
    
// parseInt() 轉換時，遇到非數字就直接返回
    parseInt('123abc') // 123
    parseInt('123a4bc') // 123
    parseInt('abc') // NaN

// parseInt 無法轉換 Boolean
    parseInt(true) // NaN 
    
// parseInt 只轉換整數, 小數點沒有解析
parseInt('123.1') // 123
```
```python
# 用正則試試看
In [23]: a = '100'
In [24]: b = 'abc100'
In [25]: c = '100abc' 

In [27]: print(re.match(r"\d+", a))
<re.Match object; span=(0, 3), match='100'>
In [28]: print(re.match(r"\d+", b))
None
In [29]: print(re.match(r"\d+", c))
<re.Match object; span=(0, 3), match='100'>
```

> - parseFloat(var)
```javascript=
// 除了可以解析小數點外，其他都跟parseInt一樣

parseFloat('100') // 100
parseFloat('100.1') // 100.1
parseFloat('100.1.1') // 100.1
parseFloat('100.abc') // 100
parseFloat('abc') // NaN
parseFloat(true) // NaN
```
```python
# 正則試試看
In [20]: a = '100'
In [21]: b = '100ba4c'
In [22]: c = 'abc100'
In [23]: d = '100.1' 
In [24]: f = '100.1.1'
In [26]: g = '100.abc' 

In [27]: print(re.match(r"\d+.?\d+", a))
<re.Match object; span=(0, 3), match='100'>
In [28]: print(re.match(r"\d+.?\d+", b))
<re.Match object; span=(0, 3), match='100'>
In [29]: print(re.match(r"\d+.?\d+", c))
None
In [30]: print(re.match(r"\d+.?\d+", d)) 
<re.Match object; span=(0, 5), match='100.1'>
In [31]: print(re.match(r"\d+.?\d+", f)) 
<re.Match object; span=(0, 5), match='100.1'>
In [32]: print(re.match(r"\d+.?\d+", g))
<re.Match object; span=(0, 3), match='100'>
```
> - 正負號運算

```javascript=
// 看起來是 Number() 後再前面多一個正負號運算
    a = '100' // "100"
    +a // 100
    -a // -100
    a // "100"

    b = '100abc' // "100abc"
    +b // NaN

    c = '100.1' // "100.1"
    +c // 100.1

    d = '1.1.1' // "1.1.1"
    +d // NaN

    a = true // true
    +a // 1
    -a // -1

// + - 拼接與運算
    a = '123' // "123"
    
    // + 一邊是str, 另一邊是num時, 會先把num轉str後拼接
    a + 0 // "1230"
    
    // - 一邊是str，另一邊是num時, 會把str轉num後運算
    a - 0 // 123
    
    
    b = '123abc' // "123abc"
    b - 0 // NaN: b 無法轉num, 故NaN
```

### 轉Boolean
> - Boolean(var)
>   - `null`, `undefined`, `''`, `0`, `NaN` 這五種會轉成 flase
```javascript=
Boolean(100) // true
Boolean('100') // true
Boolean(100.1) // true

Boolean(null) // false
Boolean(undefined) // false
Boolean('') // false
Boolean(0) // false
Boolean(NaN) // false
```

## 運算子(Operator)

### 算術運算
```javascript=
    1+1 // 2
    1-1 // 0
    1*1 // 1
    1/1 // 1

// % 餘數
    3 % 2 // 1
    5 % 2 // 1
    11 % 3 // 2
```

### 一元運算符
> - `1+1`: 二元運算，有兩個值做運算

> - 前置++
```javascript=
    a = 1 // 1
    ++a // 2 : 描述 +1+a ，返回當前a的值, +1+1=2
    a // 2 : 他真的改變變量
```

> - 後置++
```javascript=
b = 1 // 1
b++ // 1: 描述+b+1，返回當前b的值, 1( b在前面, 還沒有+1 )
b // 2 : 執行完後b的值變 2
```
```javascript=
    var a=1; // undefined
    
// var b = ++a + ++a;
    a // 3
    b // 5
    /* 
     * 第一個 ++a的
         * 返回: +1+a = +1+1 = 2
         * a的值: 2
     * 第二個 ++a的
         * 返回: +1+a = +1+2 = 3 
         * a的值: 3
     * b = 2+3 = 5
    */

// var b = ++a + a++;
    a // 3
    b // 4
    /* 
     * ++a
         * 返回: +1+a = +1+1 = 2 
         * a的值: 2
     * a++
         * 返回: 2, 
         * a的值: 3
     * b = 2+2 = 4
    */
    
// var b = a++ + ++a;
    a // 3
    b // 4
    /* 
     * a++ 
         * 返回: 1 
         * a的值 2
     * ++a 
         * 返回 +1+a = +1+2= 3
         * a的值 3
     * b = 1+3 = 4
    */
    
// var b = a++ + a++;
    a // 3
    b // 3
    /* 
     * 第一個a++ 
         * 返回: 1
         * a的值: 2
     * 第二個a++
         * 返回: 2
         * a的值: 3
     * b = 1+2 = 3
    */
```

### 邏輯運算符
```javascript=
// && 與 (並且)
    a = true
    b = true
    a && b // true

    b = false
    a && b // false
    
// || 或
    a = true
    b = true
    a || b // true

    b = false
    a || b // true

// ! 取反, 一元運算符
    a = true
    b = false
    !a // false
    !b // true
```

### 關係運算符

```javascript=
// < (小於) >(大於) >=(大於等於) <=(小於等於)  

// ==(等於) !=(不等於) ===(等於) !==(不等於)
/* 
 * == 跟 === 都是判斷兩者是否相等,
 * 差別在於 == 只判斷值是否相等
 * === 判斷類型與值是否相等
 * !== 與 !=== 亦同
 */
    a = 10
    b = 10
    a == b // true
    a === b // true

    b = '10'
    a == b // true
    a === b // false: b的類型是str, a類型是num, 所以 false
```

### 賦值運算符
```javascript=
// = 
   a == 100 // Error: a is not defined
   a = 100 // a 賦值 100
   a == 100 // true
 
// += -= *= /= %=

    a = 100
    a = a + 100 // 200

    a = 100
    a += 100 // 200: 這句話就是 a = a + 100 的簡寫
    b -= 100 // b = b - 100
    c /= 100 // c = c / 100
    d *= 100 // c = c * 100
    e %= 100 // e = e % 100
```

### 運算符優先級
> 1. `()`
> 2. `一元` : `++ -- !`
> 3. `算數` : 先 `* / %` 後 `+ -`
> 4. `關係` : `> < >= <=`
> 5. `相等` : `== === != !==`
> 6. `邏輯` : 先 `&&` 後 `||`
> 7. `賦值` : `= += -= *= /= %=`
```javascript=
// Q. 4 >= 6 || '5566' != '不能亡' && !(12 * 2 == 144) && true
    /* 
     * !(12*2 == 144) = !0 = 1
     * '5566' != '不能亡' = 1
     * 4 >= 6 = 0
     * 0 || 1 && 1 && 1
         * 0 || 1 = 1
    */

// Q. var num = 10;
//    5 == num / 2 && (2 + 2 * num).toString() === '22'
    /* 
     * (2+2*num).toString() === '22' = '22' === '22' = 1
     * 5 == num/2 = 5 == 5 = 1
     * 1 && 1 = 1
     */
```

### 冷知識

```javascript=
0>null // false
0<null // false
0=null // false

0>=null // true
0<=null // true

// ?
```
> - 他運算 >= 跟 <= 的方法是看有沒有 < 或 >
>   如果 true 或 undefined 就返回 false, 沒有就返回 true
>   - `0 >= null` -> `0 < null // false`, 
>      0 不小於 null, 所以 0>=null

> - https://www.ecma-international.org/ecma-262/5.1/#sec-11.8.4
> - Let r be the result of performing abstract relational comparison lval < rval.
> - If r is true or undefined, return false. Otherwise, return true.





## 表達式與語句
### 表達式( Expression )
> - 表達式可以產生一個值, 如運算, 調用函數等
> - 例如 `5+5` 得到10; `String(5)` 得到 '5'

### 語句
> - code 的每句話都是語句, 每一句語句都用 `;` 分開

## 分支結構
### IF
```javascript=
/* 
if ( 條件1 ) {
    執行1
} else if ( 條件2 ) {
    執行2
} else if ( 條件3 ){
    執行3
} else {
    執行4
}
*/


    var num1 = 10;
    var num2 = 5;

// Q. 判斷兩個值得大小
    if (num1 > num2) {
        'MaxNum: ' + num1
    } else if (num1 < num2){
        'MaxNum: ' + num2
    }; // "MaxNum: 10"
    
    

// Q. 判斷值是奇數還是偶數
    if (num1%2 === 0) {
        'num1 is even'
    } else {
        'num1 is odd'
    }; // "num1 is even"

// Q. 轉換成績
//    >=90: A; 
//    80-89: B; 
//    70-79: C; 
//    60-69: D; 
//    <60: F;

    var score = 80;

    /* 錯誤寫法
    if (score>=90) {
        score = 'A'
    } else if (90>score>=80) { // 數學是這樣寫, 但程序不行, 程序要拆開
        score = 'B'
    } else if (80>score>=70) {
        score = 'C'
    } else if (70>score>=60) {
        score = 'D'
    } else if (60>score) {
        score = 'E'
    };
    */

    /* 精確的寫法
    if (score>=90) {
        score = 'A'
    } else if (score>=80 && score<90) { 
        score = 'B'
    } else if (score>=70 && score<80) {
        score = 'C'
    } else if (score>=60 && score<70) {
        score = 'D'
    } else { 
        score = 'E'
    } */
    
    
    /* 由於分數大於等於90分就會執行 score = 'A' 而不會繼續往下判斷
     * 所以判斷過的語句就都可以省略掉了 */
    if (score>=90) { // 判斷完這句, 如果沒有執行, 表示值小於 90 而往下繼續判斷
        score = 'A'
    } else if (score>=80) { // 判斷之前, 值已是小於 90 了, 所以不用重複寫 
        score = 'B'
    } else if (score>=70) { // 判斷之前, 值已是小於 80 了, 所以不用重複寫
        score = 'C'
    } else if (score>=60) { // 判斷之前, 值已是小於 70 了, 所以不用重複寫
        score = 'D'
    } else { 
        score = 'E'
    }

// Q. 判斷年紀是否大於18

    var age = 19;
    
    if (age>18) {
        'age:' + age + ' > 18'
    } else {
        'age:' + age + ' < 18'
    }

// Q. 判斷是否為閏年(可以被4整除, 但不是被100整除, 或是可以被400整除)

    if (year%4 === 0 && year%100 !== 0 || year%400 === 0) {
        '閏年'
    } else {
        '不是閏年'
    }
```

### 三元表達式
> - `if (){}else{};` 的縮寫
```javascript=
// 表達式1 ? 表達式2 : 表達式3;
    /* 
     * 如果表達式1成立, 就執行表達式2, 否則執行表達式3
     * 相當於: 
     * if (表達式1) {
     *     表達式2
     * } else {
     *     表達式3 
     * };
    */ 

// 例1
    /* 
    if (num1 > num2) {
            '已成年'
        } else if (num1 < num2){
            '未成年'
        };
    */
    // num1 > num2 ? '已成年' : '未成年';
    var MaxNum = num1 > num2 ? num1 : num2;
    
// 例2
    /*
    if (age>18) {
        'age:' + age + ' > 18'
    } else {
        'age:' + age + ' < 18'
    }
    */
    // age>18 ? 'age:'+age+'>18' : 'age:'+age+'<18'
    var Tommy = TommyAge > 18 ? '已成年': '未成年';
```

### Switch
> - 判斷 Expression( 表達式 ) 的值是否與 Constant( 常量 ) 相等
> - 亦即 Switch 只能做相等判斷

> - Switch 是用 `===` 來判斷的
> - 執行語句最後記得加 `break;` 跳出, 否則他會一直執行到 `break;` 或 結束
```javascript=
// switch (Expression) {
//     case Constant1:
//         語句1;
//         break;
//     case Constant2:
//         語句2;
//         break;
//     case ...:
//         ...;
//         break;
//     default:
//         語句;
//         break;
// }

    var day = 2;

/* 
 * 明明有設 '2' , 結果卻是 default ?
 * 因為 switch是用 === 判斷, 所以前面兩個都是 false
 * 
    switch (day) {
        case '1':
            console.log('星期一');
            break;
        case '2':
            console.log('星期二');
            break;
        default:
            console.log('我只有設星期一跟星期二, 我就是傲嬌');
            break;
    } // '我只有設星期一跟星期二, 我就是傲嬌'
*/


    switch (day) {
        case 1:
            console.log('星期一');
            break;
        case 2:
            console.log('星期二');
            break;
        default:
            console.log('我只有設星期一跟星期二, 我就是傲嬌');
            break;
    } // '星期二'
    
/* 記得每個判斷後都要跳出 break; 
 * 否則他會一直輸出到 break; 或 最後一行為止
 * 
    var day = 1;
    switch (day) {
        case 1:
            console.log('星期一');
        case 2:
            console.log('星期二');
        case 3:
            console.log('星期三');
        default:
            console.log('我只有設星期一跟星期二, 我就是傲嬌');
    } // 星期一
      // 星期二
      // 星期三
      // 我只有設星期一跟星期二, 我就是傲嬌
*/


// 轉換分數


    var score = 90
    /* 吃飽太閒法:
    switch (score) {
        case 100:
        case 99:
        case 98:
        // ...
        case 90:
            score = 'A';
    } // "A"
    score // "A"
    */
    
    score = parseInt(score/10);
    switch (score) {
        case 10:
        case 9:
            score = 'A';
            break
        case 8:
            score = 'B';
            break
        case 7:
            score = 'C';
            break
        case 6:
            score = 'D';
            break
        default:
            score = 'E';
            break
    } // "A"
```

### Boolean 隱式轉換

```javascript=
// 顯示轉換
    /* var a = 100;
     * Boolean(a) // true
     */
     
// 隱式轉換
// if 判斷的時候會轉Boolean後判斷true, false

    /*
    var a = 100;
    if (a) {
        console.log('true')
    } else {
        console.log('false')
    } // true
    */
    var a; // NaN, 0, '', undefined, null
    if (a) {
        console.log('true')
    } else {
        console.log('false')
    } // false
    
// ! 取反運算
    var a = '123' // undefined
    a // "123"
    var a = !'123' // undefined
    a // false
    var a = !!'123' // undefined
    a // true
```

## 循環結構
### while

```javascript=
/* while () {
 * }
 */
 
/* Python
In [4]: i = 1
In [5]: while i <= 10: 
   ...:     print(i) 
   ...:     i+=1 
*/ 
 
     var i = 1;
     while (i<=10) {
         console.log(i);
         // i = i + 1;
         // i+=1;
         i++;
     }
     
/*  Python
In [21]: i = 1 
In [22]: j = 0 
In [24]: while i <= 10: 
    ...:     j = j + i 
    ...:     i += 1 
*/

    var i = 1;
    var j = 0;
    while (i <= 10) {
        j+=i;
        i+=1;
    }
    console.log(i,j);
    
/* Python
In [41]: i = 1
In [42]: while i <= 100: 
    ...:     if i%7 == 0: 
    ...:         print(i) 
    ...:     i+=1 
*/

    var i = 1;
    while (i<=100) {
        if (i%7 === 0) {
            console.log(i)
        }
        i+=1;
    }
    
/* python
In [67]: i = 0
In [68]: j = 0 
In [69]: while i <= 100: 
    ...:     if i%2 == 0: 
    ...:         j+=i 
    ...:     i+=1 
*/

    var i = 0
    var j = 0
    while (i<=100) {
        if (i%2 === 0) {
            j+=i
        }
        i+=1
    }
    console.log(i,j) // 101, 2550
```

### do...while...
> - 特色: 會先執行一次循環體後再判斷

```javascript=
/* 語法
do {
    // 循環體
} while (條件)

 * 先執行一次do, 
 * 如果while條件為 true, 
 * 繼續執行do
*/

var i = 0;
var j = 0;

/*
while (i<=100) {
    j+=i
    i+=1
}
console.log(i,j); // 101, 5050
*/

do {
    j+=i
    i+=1
} while (i<=100)
console.log(i,j); // 101, 5050


// 恐怖情人

/* while 的寫法
var msg = prompt('你愛我嗎?', '請填入Y/N')
while (msg !== 'Y') {
    msg = prompt('你愛我嗎?', '請填入Y/N')
}
*/

do { // 用 do 先問一次, 比較簡潔一點點
    var msg = prompt('你愛我嗎', '請填入Y/N');
} while (msg !== 'Y')

```

> - prompt('', '')
>   - `prompt('hihi', 'wiwi')`
>     <img src="https://i.imgur.com/H11Cu7d.png" style="width: 300px;"/> 
>     - 第二個參數類似於 `<input type='text' value:'wiwi'/>` 的 value

```javascript=
prompt('hihi', 'wiwi'); // "123" : 返回一個str
```

### for
> - 跟Python很不一樣

```javascript=
/*
for (初始化表達式(1); 判斷表達式(2); 自增表達式(3)) {
    // 循環體(4)
}
 * (1)>(2)>(4)>(3)>(2)>(4)>(3)>...
 * 注意(1);(2);(3) 是分號隔開，不是逗號！
*/

    /* while
    var i = 0; // (1)
    while (i <= 100) { // (2)
        console.log(i); // (4)
        i+=1; // (3)
    }
    */

    for (var i=0; i<=100; i+=1){
        console.log(i);
    } 

/* for的表達式是可以省略的
    var i = 0;
    for (;i<=100;) { // 1. ; 不能省 2. 判斷條件省了就會一直true而造成死循環
        console.log(i)
        i+=1
    }
*/

// 1-100 sum, avg
    var sum = 0;
    var avg;
    for (var i=1; i<=100; i+=1) {
        sum+=i
    }
    console.log(i, sum) // 101, 5050
    avg = sum/(i-1)
    console.log(avg)

// 0-100 偶數和
    var sum = 0; // 記得要讓sum附值, 否則NaN沒辦法運算(註)
    for (var i=1; i<=100; i+=1) {
        if (i%2 === 0) {
            sum+=i;
        }
    }
    console.log(i, sum)
    /* 註
       a = NaN // NaN
       a + 1 // NaN
    */

// 0-100 奇數和 與 偶數和

    var oddSum = 0
    var evenSum = 0
    for (var i=0; i<=100; i+=1) {
        if (var i%2 === 0) {
            evenSum+=i
        } else {
            oddSum+=i
        }
    }
    console.log('奇數和: ' + oddSum)
    console.log('偶數和: ' + evenSum)
    
// ---------------------------- //    

// 輸出10*10的星星排列正方形

/* Python 解一
In [38]: a = '' 
In [39]: for i in range(10): # 10行
    ...:     for j in range(10):  # 一行10個
    ...:         a+="* " 
    ...:     a+="\n" 
In [40]: print(a)
*/

    var a = '';
    for (var i=0; i<10; i+=1) { // 10行
        for (var j=0; j<10; j+=1) { // 10列
            a+='* ';
        }
        a+='\n'
    }
    console.log(a)
    
/* python 解二
In [64]: for i in range(10): 
    ...:     print("* "*10) 
*/    

    /* js 的 str好像不能乘
    a = '*' // "*"
    a*10 // NaN
    */

// ---------------------------- //

// 輸出 10*10 正三角
/* python 解一
In [83]: a = ''   
In [84]: for i in range(10):  # 十行
    ...:     for j in range(i):  # 第一行一個, 第二行兩個
    ...:         a+='* ' 
    ...:     a+='\n'
In [85]: print(a)
*/
    /* JS 解 1-1 */
    var a = '';
    for (var i=1; i<=10; i+=1) {
        for (var j=i; j>0; j-=1) { // 第一行一個
            a+="* ";
        }
        a+='\n'
    }
    console.log(a);
    
    /* JS 解 1-2 */
    var a = '';
    for (var i=9; i>=0; i-=1) {
        for (var j=i; j<10; j+=1) { // 第一行一個
            a+="* ";
        }
        a+='\n'
    }
    console.log(a);
    

/* python 解二
In [82]: for i in range(10): 
    ...:     print('*'*i)
*/

// --輸出10*10 的倒三角形-------------------------- //
 
/* python 解一
In [94]: a = '' 
In [96]: for i in range(10,0,-1): 
    ...:     for j in range(i): 
    ...:         a+='* ' 
    ...:     a+='\n'
In [97]: print(a) 
*/

    /* jS解 1-1 */
    var a = ''
    for (var i=10; i>0; i-=1) {
        for (var j=i; j>0; j-=1) { // 第一行十個
            a+='* '
        }
        a+='\n'
    }
    console.log(a)
    
    /* JS 解 1-2 */
    var a = ''
    for (var i=0; i<10; i+=1) {
        for (var j=i; j<10; j+=1) { // 第一行十個
            a+='* '
        }
        a+='\n'
    }
    console.log(a)

/* python 解二
In [62]: for i in range(10,0,-1): 
    ...:     print("* "*i) 
*/

// --九九乘法表--------------------- //

/* Python
In [108]: for i in range(1,10): 
     ...:     for j in range(1,10): 
     ...:         print('%d*%d=%-2d ' % (i,j,i*j), end='') 
     ...:     print('\n') 
  # %2d: 數字寬度為2, 如果只有一位數, 向右對齊, 左邊補空格
  # %-2d: 數字寬度為2, 如果只有一位數, 向左對齊, 右邊補空格
  # %02d: 數字寬度為2, 如果只有一位數, 向右對齊, 左邊補0 (%.2d也一樣)
*/

var a = ''
for (var i=1; i<10; i+=1) {
    for (j=1; j<10; j+=1) {
        // a+=(i+'*'+j+'='+i*j+' '); : 有些結果個位數，有些十位數，
                                    // 位置會跑掉, 所以改'\t'
        a+=(i+'*'+j+'='+i*j+'\t');
    }
    a+=('\n');
}
console.log(a)

// 三角形九九乘法表

var a = ''
for (var i=1; i<10; i+=1) {
    for (var j=i; j<10; j+=1) {
        a += (i+'*'+j+'='+i*j+'\t')
        }
    a+='\n'
}
console.log(a)

// Q. 本金10000元存入銀行，年利率是千分之三，
//    每過1年，將本金和利息相加作為新的本金。計算5年後，獲得的本金是多少？ 
/* python
In [30]: money = 10000
In [31]: for i in range(1,6): 
    ...:     money = money * 1.003 
In [32]: money                       
Out[32]: 10150.902704052423
*/

    var money = 10000;
    for (i=1; i<=5; i++) {
        money *= 1.003;
    }
    console.log(money); // 10150.902704052423
    
// Q. 有個人想知道，一年之內一對兔子能繁殖多少對？於是就築了一道圍牆把一對兔子關在裡面。
//    已知一對兔子每個月可以生一對小兔子，而一對兔子從出生後第3個月起每月生一對小兔子。
//    假如一年內沒有發生死亡現象，那麼，一對兔子一年內（12個月）能繁殖成多少對？ 
//    （兔子的規律為數列，1，1，2，3，5，8，13，21）

/* python
In [78]: firstMonth = 1 
In [79]: secondMonth = 1 
In [80]: Month = 0
In [81]: for i in range(3,13): 
    ...:     Month = firstMonth + secondMonth 
    ...:     firstMonth = secondMonth 
    ...:     secondMonth = Month 
    ...:     print(Month)                              
2
3
5
8
13
21
34
55
89
144
*/

    var firstMonth = 1;
    var secondMonth = 1;
    var Month = 0
    for (var i=3; i<=12; i++) {
        Month = firstMonth + secondMonth;
        firstMonth = secondMonth;
        secondMonth = Month;
        // console.log(firstMonth, secondMonth,Month);
    }
    console.log(Month); // 144
```

### break & continue
> - break : 跳出整個循環, 終止循環
> - continue : 跳出這次循環，繼續下一次循環

```javascript=
// Q. 求 50 - 200 首個能被 7 整除的數
/* Python
In [66]: for i in range(50, 201): 
    ...:     if i % 7 ==0: 
    ...:         print(i) 
    ...:         break                            
56
*/
    for (var i=50; i<=200; i++) {
        if (i % 7 === 0) {
            console.log(i)
            break
        }
    } // 56

// Q. 求 1-100 累加, 但跳過個位數為3的值
/* Python
In [71]: Sum = 0 
In [75]: for i in range(0,101): 
    ...:     if i % 10 != 3: 
    ...:         Sum+=i 
In [76]: Sum                           
Out[76]: 4570
*/
    // 解一
    var sum = 0
    for (var i=1; i<=100; i++) {
        if (i%10 !== 3) {
            sum += i
        }
    } // 4570
    
    // 解二(continue)
    var sum = 0;
    for (var i = 1; i<=100; i++) {
        if (i%10 === 3) {
            continue // 餘數為3時, 跳出當次循環
        }
        sum += i
    } // 4570
    
// Q. 1-100 不能被7整除的和(continue)
    var sum = 0
    for (var i = 1; i <= 100; i++) {
        if (i%7 === 0 ) {
            continue;
        }
        sum+=i;
    } 

```

## 調適(Debug)

### 語法錯誤: 打錯
> - `for (i=100, 1<1000, 1++) {}`
>   ![](https://i.imgur.com/Sg2Umzx.png)
>   ![](https://i.imgur.com/7FcfZAJ.png) 
>

### 邏輯錯誤:

```javascript=
// Q. 算1-100的和
/*
var sum = 1;
for (var i=1; i<100; i++) {
    sum+=1;
}
console.log(sum); // 100 : 跟預期的結果有很大的出入
*/
```

> #### 調適方法
> - alert()
>   ![](https://i.imgur.com/sPic4QD.png)
>   - 一個一個跳結果出來, 缺點就是一定要跳完，不然就是關掉, 不是很好用
```javascript=
var sum = 1;
for (var i=1; i<100; i++) {
    sum+=1;
    alert(sum);
}
console.log(sum);
```
>   - console.log()
>     - 類似 python 的 print
>     ![](https://i.imgur.com/CTYhjZz.png)
```javascript
var sum = 1;
for (var i=1; i<100; i++) {
    sum+=1;
    console.log(sum);
}
console.log(sum);
```
>   - 斷點調適
>     - 類似 Python 的 PDB
>     - 什麼都沒做時
>     ![](https://i.imgur.com/tJ31pCF.png)
>     - 點一下行數會產生標記，此時code會執行到標記的上一行止
>     ![](https://i.imgur.com/OTkwKlh.png)
>     ![](https://i.imgur.com/7N2IGtq.png)
>     - 點擊下的圖標，標記會跳到下一行
>     ![](https://i.imgur.com/Gieu7mK.png)
>     ![](https://i.imgur.com/Dio50xY.png)
>     ![](https://i.imgur.com/TTm0XnM.png)


## 陣列(Array)
`[, , ,...]`
```javascript=
// 有序列表
// 可裝不同類型
var arr = [1, 1.1, 'haha', true, undefined, null]

// 提取: 陣列名[下標/索引]
   // 下標第一個為0, 最後一個為陣列長度-1
arr[0] // 1
arr[1] // 1.1
arr[4] // undefined
arr[5] // null
arr[6] // undefined

// 陣列長度: `陣列名.length`
console.log(arr.length) // 6 

// 提取最後一個元素: 陣列名[陣列長度-1]
console.log[arr[arr.length-1]] // null


// 改
// 陣列名[下標/索引] = 附值, 下標下 長度-1內 的值
var arr = [1,2,3,4]
arr[0] // 1
arr[0] = 9 // 11
console.log(arr); // (4) [9, 2, 3, 4]

// 增
// 陣列名[下標/索引] = 附值, 下標下 超出長度-1 的值
    // 沒有超出的部分會自動補 undefined
    
var arr = [1,2,3,4]
arr[6] = 0
console.log(arr); // (7) [1, 2, 3, 4, empty × 2, 0]
arr[5] = undefined

// 遍歷陣列
var arr = [1,2,3,4] // undefined
for (i=0; i<arr.length; i++) {
	console.log(arr[i])
}

// 倒敘遍歷
var arr = [1,2,3,4]
for (i=arr.length-1; i>=0; i--) {
    console.log(arr[i]);
}

// 應用
var test = [];
for (i=0; i<5; i++) {
    test[i] = i;
}
console.log(test); // (5) [0, 1, 2, 3, 4]

// 清空陣列
var arr = [1,2,3,4]

arr.length = 0
console.log(arr); // []


// Q. 求一組數中所有數的和與平均值
  var arr = [1,2,3,4,];
  var sum = 0;
  var avg;
  for (var i=0; i<4; i++) {
    sum += arr[i];
  }
  avg = sum/arr.length;
  console.log('和: ' + sum);
  console.log('平均: ' + avg);

// Q. 求一組數中最大值與最小值, 以及所在位置
  var arr = [11,2,44,14,32];
  var max = arr[0];
  var min = arr[0];
  var maxIndex = 0; // 避免第一個值就是最大值而造成maxIndex到循環結束都沒有賦值
  var minIndex = 0;
  for (var i=1; i<arr.length; i++) {
    if (max < arr[i]) {
      max = arr[i]
      maxIndex = i
    }
    if (min > arr[i]) {
      min = arr[i]
      minIndex = i
    }
  }
  console.log('最大值: ' + max + '; 位置在: ' + maxIndex);
  console.log('最小值: ' + min + '; 位置在: ' + minIndex);

// Q. 將字符串陣列用 | 隔開，形成一串字符串
  // 解一
  var strs= ['1', '2', '3', '4'];
  var str = '';
  var separator = ' | ';

  for (i=0; i<strs.length; i++) {
      if (i<strs.length-1) {
          // str = str + strs[i] + ' | ' // 避免在表達式中寫一個固定的值
          str = str + strs[i] + separator;
      } else {
          str = str + strs[i];
      }
  }

  // 解二
  var strs= ['1', '2', '3', '4'];
  var str = strs[0];
  var separator = ' | ';

  for (i=1; i<strs.length; i++) {
      // str = str + separator + strs[i];
      str += separator + strs[i];
  }

// Q. 將陣列第0項移除, 將陣列中不為0的值存入新陣列
  var nums = [2,4,66,0,21,0,13];
  var newNum = [];
  for (i=1; i<nums.length; i++) {
    if (nums[i] !== 0) {
      // newNum[i]=nums[i] 
        // (7) [empty, 4, 66, empty, 21, empty, 13]
        // 問題: 形成一個不連續的陣列
      newNum[newNum.length] = nums[i]; // (4) [4, 66, 21, 13] // 註
    }
  }
  console.log(newNum);

  // 註:
  var test = [];
  console.log(test.length); // 0

  test[test.length] = 3;   
  console.log(test.length); // 1

  test[test.length] = 88;
  console.log(test.length); // 2

  console.log(test); // (2) [3, 88]
  
// Q. 反轉陣列
var arr = [1,2,3,4]; // > [4,3,2,1]
var newArr = [];
for (var i=arr.length-1; i>=0; i--) {
  newArr[newArr.length] = arr[i];
}
arr = newArr;
console.log(arr);


// Q. 冒泡排序
/* 每次兩個位置比較, 跑一圈就會決定最後一個的值, 
 * 確定之後就不用跑了, 所以每圈-1次比較次數 */
/*
[0] [1] [2] [3] n = length = 4
第一次 [0]<>[1] [1]<>[2] [2]<>[3] > 確定[3] n-1 > n-j
第二次 [0]<>[1] [1]<>[2] > 確定[2] n-2 > n-j
第三次 [0]<>[1] > 確定[0], [1] n-3 > n-j
n-1圈
*/

var alist = [54,26,93,17,77,31,44,55,20];
var count = 0; // 紀錄大O

// 控制趟數, 每趟找到一個最大值
for (j=1; j<alist.length; j++) { // 假設n=4, j=1~3(3圈)<4
  count++; // 記錄一下大O
  console.log('第'+ j + '圈');
  var isSort = true; // 假設序列已經排好了
  
  // 控制比較次數，判斷大小，大的往後移
  for (var i = 0; i<alist.length-j; i++) { // j=1, i=0~2<(4-1); > 三次
                                           // j=2, i=0~1<(4-2); > 兩次
                                           // j=3, i=0~0<(4-3); > 一次
    count++; // 算一下大O
    // 如果前面比後面大
    if (alist[i] > alist[i+1]) { 
      // 交換
      var temp = alist[i];
      alist[i] = alist[i+1];
      alist[i+1] = temp;
      // 有交換表示還沒排序完成, 改成false;
      isSort = false;
    }
    console.log(alist); // 監控作用
  }
  console.log(isSort);
  // 內圈整趟比較完後, 如果都沒有進入if交換, 表示排序完成而不用在跑下一圈了
  if (isSort) {
    break
  }
}
console.log(count) // 看總共跑多少圈循環
/* 
 * [17, 20, 26, 31, 44, 54, 55, 77, 93]
 * 28
*/
```