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++) {}`
> 
> 
>
### 邏輯錯誤:
```javascript=
// Q. 算1-100的和
/*
var sum = 1;
for (var i=1; i<100; i++) {
sum+=1;
}
console.log(sum); // 100 : 跟預期的結果有很大的出入
*/
```
> #### 調適方法
> - alert()
> 
> - 一個一個跳結果出來, 缺點就是一定要跳完,不然就是關掉, 不是很好用
```javascript=
var sum = 1;
for (var i=1; i<100; i++) {
sum+=1;
alert(sum);
}
console.log(sum);
```
> - console.log()
> - 類似 python 的 print
> 
```javascript
var sum = 1;
for (var i=1; i<100; i++) {
sum+=1;
console.log(sum);
}
console.log(sum);
```
> - 斷點調適
> - 類似 Python 的 PDB
> - 什麼都沒做時
> 
> - 點一下行數會產生標記,此時code會執行到標記的上一行止
> 
> 
> - 點擊下的圖標,標記會跳到下一行
> 
> 
> 
## 陣列(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
*/
```