Program Structure
===
###### tags: `共筆` `Javascript`
## Bindings
在之前我們學會了利用值 (value) 去產生新的值,但是新產生出來的值不馬上使用就會消失。
綁定 (Binding)讓我們可以把值保存起來
```javascript=
let caught = 5 * 5;
```
`let` 代表定義一個綁定,`caught` 代表要被綁定的名稱,可以使用 `=` **給值 (assign)**。
當綁定指向某個值的時候,並不代表永遠與該值綁定。
可以隨時使用 `=` 重新綁定。
```javascript=
var mood = "light";
console.log(mood);
// → light
mood = "dark";
console.log(mood);
// → dark
```
當定義一個綁定卻沒有賦予值的時候,會返回 `undefined`。
一個 `let` 可同時定義多個綁定,以逗號分隔。
```javascript=
let one = 1, two = 2;
console.log(one + two);
// → 3
```
`var` 和 `const` 也可以用來定義綁定。
`var` 與 `let` 類似但有些微不同,在後面會講到確切的不同之處。
`const` 代表 constant,定義一個不變的綁定,永遠指向相同的值並且不可重新綁定。
```javascript=
const example = 10;
example = 20;
// → Uncaught TypeError: Assignment to constant variable.
```
> 平常比較常用的說法是宣告變數 (declare variable)
> [name=阿月] [time=Sun, Nov 6, 2022 3:43 PM] [color=#FFBF00]
### Binding names
**綁定名稱 (Binding names)** 可以是任何單字,數字也可以是名稱的一部分,==但是不能以數字開頭==。
例如 `catch22` 就是一個有效的名稱。
名稱內也可以包含 `$` 和 `_` ,但不可以包含其他標點符號或特殊符號。
具有特殊涵義的詞,例如 `let`,是 *keywords*,不能用來當作綁定名稱。 還有其他保留使用的單字,也不可當作名稱使用,例如以下這些:
```javascript
break case catch class const continue debugger default
delete do else enum export extends false finally for
function if implements import interface in instanceof let
new package private protected public return static super
switch this throw true try typeof var void while with yield
```
不用擔心記不住,若使用到保留單字作為綁定名稱時會產生 unexpected syntax error。
## Functions
**函數 (Function)** 是一段包好的程式碼,可以利用輸入的值來運行程式碼。
例如:`prompt` 是一個函數,可以顯示一個小對話框並且讓使用者可以輸入內容。
```javascript=
prompt("Enter passcode");
```

執行函數可以稱為 invoke、call、apply。
在上面例子中,`prompt` 利用我們提供的字串作為文字顯示在對話框中。
這樣提供給函數的值被稱為**參數 (arguments)**。
不同函數可能需要不同數量或不同類型的參數。
### The `console.log` function
`console.log` 函數可以將輸入的參數顯示在 javascript console 中。
```javascript=
let x = 30;
console.log("the value of x is", x);
// → the value of x is 30
```
### Return values
函數也可能產生值,例如 `Math.max` 可以接收任意數量的參數並且回傳最大值。
```javascript=
console.log(Math.max(2, 4));
// → 4
```
當一個函數產生值的時候,稱為 **返回/回傳 (return)** 該值。
## Control flow
當程式碼包含多個**語句 (statement)** 時,這些語句會從上到下依序執行。
以下面程式碼為例,這個程式碼有兩個 statement
第一句讓使用者輸入數字
第二句在第一句執行完之後才執行,會顯示該數字的平方
```javascript=
let theNumber = Number(prompt("Pick a number"));
console.log("Your number is the square root of " +
theNumber * theNumber);
```
因為 `prompt` 回傳的值是字串,`Number` 函數可以將字串轉換成數字。
類似的函數還有 `String` 和 `Boolean`,可以將值轉換為該類型。
#### straight-line control flow
直線運行程式的 control flow

#### Conditional execution
並非所有的程式都是直線運行的。
如果希望程式依照特定條件執行適當的程式,稱為**條件執行 (Conditional execution)**

我們可以使用 `if (條件式)` 和 `else` 來達成這個結果,代表當某些條件成立時才執行某些特定程式碼,不成立時則執行另外的程式碼。
如以下範例,只有當輸入是數字時,才會顯示輸入的平方,輸入非數字時,則顯示字串。
```javascript=
let theNumber = Number(prompt("Pick a number"));
if (!Number.isNaN(theNumber)) {
console.log("Your number is the square root of " +
theNumber * theNumber);
} else {
console.log("Hey. Why didn't you give me a number?");
}
```
`isNaN(參數)` 當輸入的參數是 NaN 時才返回 `true`。
如果需要多個條件時,可以將 `if` 和 `else` 接在一起使用。
```javascript=
let num = Number(prompt("Pick a number", "0"));
if (num < 10) {
console.log("Small");
} else if (num < 100) {
console.log("Medium");
} else {
console.log("Large");
}
```
這段程式碼的 control flow

## Loops
### `while` and `do`
假設現在想要編寫一個程式,輸出 0 到 12 的所有偶數,其中一種編寫方式如下:
```javascript=
console.log(0);
console.log(2);
console.log(4);
console.log(6);
console.log(8);
console.log(10);
console.log(12);
```
但是當數字範圍很大時,以上方法顯然不可行,此時可以運用 **迴圈 (Loop)** 簡寫成以下程式碼:
```javascript=
let number = 0;
while (number <= 12) {
console.log(number);
number = number + 2;
}
// → 0
// → 2
// … etcetera
```
以上程式碼的 control flow

<br>
Example 2. 計算 2 的 10 次方
* result 用來儲存 2 的 10 次方結果
* counter 則是用來記錄目前算到幾次方。
```javascript=
let result = 1;
let counter = 0;
while (counter < 10) {
result = result * 2;
counter = counter + 1;
}
console.log(result);
// → 1024
```
`do` 類似於 while,區別在於 do 是先執行完一次之後才判斷迴圈條件。
```javascript=
let yourName;
do {
yourName = prompt("Who are you?");
} while (!yourName);
console.log(yourName);
```
### Indenting Code 縮排
**縮排** 是為了讓程式結構易於理解 (非必需)。
<br>
### `for` loop
#### while loop 例子
```javascript=
let result = 1;
let counter = 0;
while (counter < 10) {
result = result * 2;
counter = counter + 1;
}
console.log(result);
// → 1024
```
以剛剛 while loop 的例子,counter 用來計數、判斷是否結束迴圈,然後在迴圈結束時更新 counter,這樣的迴圈結構在程式碼中很常見。
`for` 迴圈更簡短且適用於這種格式。
#### for loop 例子
```javascript=
var result = 1;
for (var counter = 0; counter < 10; counter = counter + 1)
result = result * 2;
console.log(result);
// → 1024
```
### Breaking Out of a Loop
迴圈條件為 `false` 時可以結束迴圈,除此之外還可以使用 `break` 來馬上跳出迴圈。
以下例子是找出第一個大於等於 20 且可以被 7 整除的數字。
```javascript=
for (let current = 20; ; current++) {
if (current % 7 == 0) {
break;
}
}
// → 21
```
`%` 可以用來判斷某數是否可以被另外一個數整除。
ps. 上面例子的 for 迴圈省略了終止條件。
`continue` 與 `break` 類似,作用是立即執行下一回循環。
```javascript=
for (let current = 20; current <= 30; current++) {
if (current % 2 == 0) {
continue;
}
console.log(current);
}
// → 21 23 25 27 29
```
:::info
`break` 和 `continue` 都是作用於迴圈 (僅一層)
:::
### Updating bindings succinctly
```javascript=
counter = counter + 1;
result = result * 2;
number = number - 1;
```
可以改寫成
```javascript=
counter += 1;
result *= 2;
number -= 1;
```
`counter += 1;` 可以改寫成更簡潔的 `counter++;`
` number -= 1;` 可以改寫成更簡潔的 ` number--;`
## `switch`
```javascript=
if (x == "value1")
action1();
else if (x == "value2")
action2();
else if (x == "value3")
action3();
else
defaultAction();
```
以 `switch` 可以改寫成如下:
`{ }` 內可以放置任意數量 `case`,如果找不到對應的 `case` 則會從 default 執行。
```javascript=
switch (x) {
case "value1":
action1();
break;
case "value2":
action2();
break;
case "value3":
action3();
break;
default:
defaultAction();
break;
}
```
:::danger
**需注意**
若沒有 `break`,程式會一直往下執行 (即使跨 `case`) 直到遇到 `break` 為止。
:::
## Capitalization
綁定名稱 (binding name) 不可包含空格,當一個綁定名稱要使用多個單字時可以有以下做法。
```javascript=
fuzzylittleturtle // 較難以閱讀
fuzzy_little_turtle
FuzzyLittleTurtle // 大駝峰 Pascal Case
fuzzyLittleTurtle // 小駝峰 Camel Case
```
標準 javascript 函數遵循第四種風格 -- 除了首個單字字母以外,其他每個單字的首字母均大寫。
> 通常團隊開發時會遵循統一的 naming 規則,叫做 coding style。
> coding style 通常還包含很多其他規則,主要是為了程式碼的一致性。
> [name=阿月] [time=Sun, Oct 30, 2022 3:43 PM] [color=#FFBF00]
## Comments 註解
直接看程式碼有時候很難馬上看出這些程式碼主要目的為何,此時可以使用註解。
程式執行時會完全忽略這些內容。
```javascript=
// 可以寫單行註解
/*
可以多行註解
*/
```
## Summary
程式碼按順序執行,可以使用 `if`、`else` 、`while`、`for` 等來改變程式的 control flow
## Exercises
### 2.1 Looping a triangle
:::spoiler 程式碼
```javascript=
let star = '#';
for (count = 1; count <= 7; count++) {
console.log(star.repeat(count));
}
```
:::
### 2.2 FizzBuzz
聽說這是一個可以淘汰掉很多人的面試題
:::spoiler 程式碼
```javascript=
for (number = 1; number <= 100; number++) {
let result = '';
if (number % 3 == 0) {
result += 'Fizz';
}
if (number % 5 == 0) {
result += 'Buzz';
}
console.log(result == '' ? number : result);
}
```
:::
### 2.3 Chessboard
:::spoiler 程式碼
```javascript=
let size = 15;
let result = '';
for (i = 1; i <= size; i++) {
for (j = 1; j <= size; j++) {
if ( (i+j) % 2 == 0)
result += ' ';
else
result += '#';
}
result += '\n';
}
console.log(result);
```
:::
<!------------------------------------------>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<style type="text/css">
@import url('https://fonts.googleapis.com/css?family=Proxima+Nova');
#doc {
background-color: white;
color: rgba(0,0,0,0.8);
font-family: 'Proxima Nova', 'proxima nova', sans-serif, 'Noto Sans CJK TC Light';
}
img
{
display:block;
}
/* https://stackoverflow.com/questions/14736496/use-font-awesome-icons-in-css */
.markdown-body h4:before
{
font-family: FontAwesome;
content:"\f005 ";
color:orange;
}
.markdown-body h4
{
padding:0;
/*line-height:normal;*/
height:22px;
border-bottom:2px solid;
display:inline-block;
text-align:center;
}
.ui-comment-button.empty {
margin-left:-3px;
border-bottom:2px solid;
border-color:white;
min-width:43px;
}
ul.part, dl{
margin-left: 20px;
}
dl {
border:1px #ccc dashed;
border-radius:20px;
margin-left: 20px;
}
dt:before {
font-family: FontAwesome;
content:"\f02d ";
font-style: normal;
}
dt,dd {
margin-left: 20px;
}
p.part + ul {
/* margin-top: -15px; */
/* margin-left: 20px; */
}
div > p {
margin-left: 20px;
}
strong {/* 粗體設置 */
font-weight: bolder;
color: #EF767A;
}
blockquote{
font-weight: normal;
font-size: 16px;
margin-left: 20px;
Background:#F5F5F5;
}
h3{
color: #2bac8f; /* #4B6DC1 */
}
div#doc a {
color: #2bac8f;
text-decoration: none;
padding: 5px;
border-radius: 5px;
margin: -5px; /* 換行對齊用 */
-webkit-transition: 0.5s;
-moz-transition: 0.5s;
-o-transition: 0.5s;
-ms-transition: 0.5s;
transition: 0.5s;
}
div#doc a:hover {
color: #2eb899;
text-decoration: underline;
background-color: rgba(255,201,92,0.3);
}
div#doc a:visited {
color: #2bac8f;
}
div#doc a.anchor.hidden-xs {
margin-left:-25px;
padding-right: 4px;
line-height: 1
}
.markdown-body hr {
/************ 斜線 ************//*
height: 6px;
background: url(http://ibrahimjabbari.com/english/images/hr-11.png) repeat-x 0 0;
border: 0;
/******************************/
/************ 漸變線 ************/
border: 0;
height: 1px;
background-image: linear-gradient(to right, white, rgba(222, 222, 222, 0.6), white);
/*******************************/
}
</style>