---
title: Astro課程 0805 - JavaScript (Day1)
tags: astro, javascript
---
# Part 1: 程式基礎,以JavaSript為例
看自己本地環境的`node js`版本 `node --version`
```
master node --version
v14.6.0
```
不同的javascript引擎,語法跑出來的結果不太相同
不同的js版本,LTS (長期支援 Long-term support)可能不一樣
[Production applications should only use Active LTS or Maintenance LTS releases](https://nodejs.org/en/about/releases/)
```javascript
y = `test` // string interpolation
```
```javascript
let x = 10; // 第一次出現時宣告
// 三種字串宣告方式:單引號、雙引號、反引號
let y = '100';
let a = "";
// grave, backtick 這個在js和其他程式語言的功能不一樣
let b = `test`;
let z = x + y;
console.log(z);
let userName = "John";
let greeting = "Hello, " + userName + ", how are you?";
// string interpolation
let greeting2 = `Hello, ${userName}, Nice to meet you. how are you?`;
console.log(greeting)
console.log(greeting2)
```
# 全域變數 / 區域變數
## scope 變數作用域
以前版本的`javascript`只有:
- global scope 全域變數
- function scope 函式內區域變數
ruby 還有 block scope
## 以Ruby舉例
```ruby
def foo
x = 100
end
puts x # 會出錯
# hello-ruby.rb:5:in `<main>': undefined local variable or method `x' for main:Object (NameError)
```
拿到x的方法
```ruby
def foo
x = 100
puts x
end
foo() # 100
```
scope的概念
```ruby
def foo
x = 100
puts x
end
x = 1000
puts x # 1000
```
## 以js舉例
let 放在function內(會出錯)
```javascript
function foo() {
let x1 = 100;
// ReferenceError: x1 is not defined at Object.<anonymous> (/Users/tingtinghsu/Documents/projects/astro_js/Day1/hello-foo.js:6:13)
}
foo();
console.log(x1);
```
```javascript
let x1 = 100;
function foo() {
//let x1 = 100;
}
foo();
console.log(x1); //=> 100
```
如果放在function內但不宣告 => 變成全域變數
```javascript
function foo() {
x1 = 100;
}
foo();
console.log(x1); //=> 100
```
行為良好的程式語言是否該取得`i`?
```javascript
for (var i = 0; i < 10; i++) {
}
console.log(i); // => 會印出10
```
為了不要讓`i`被取得,使用`let`
(超過可以使用的範圍再取用時就會噴錯)
```javascript
for (let i = 0; i < 10; i++) {
}
console.log(i);
ReferenceError: i is not defined
at Object.<anonymous> (/Users/tingtinghsu/Documents/projects/astro_js/Day1/for.js:4:13)
```
let是新的語法
(rails webpacker: 拿到js的新語法,翻譯成大部分瀏覽器可以使用的舊語法)
比起`var`,用`let`的好處
```javascript
function bar(x) {
for (var j = 0; j < x; j++) {
// 1. 拿得到 j
}
// 2. 拿得到 j
}
// 3. 拿不到 j
```
```javascript
function bar(x) {
for (let j = 0; j < x; j++) {
// 1. 拿得到 j
}
// 2. 拿不到 j
}
// 3. 拿不到 j
```
# 變數提升:把變數的宣告提升到檔案的最上層
```javascript
var userName1 = "Johnny Doe"
console.log(userName1); // Johnny Doe
```
兩句交換,後為什麼會印出`undefined`?
```javascript
console.log(userName);
var userName = "John Doe" // undefined
```
```javascript
console.log(userName);
var userName = "John Doe" //
//javascript直譯器跑完檔案時,會把上面那句話拆成兩層,
//然後`var userName`會被提升到檔案最上層
var userName
userName = "John Doe"
```
# Function 函式
回傳值`return`和`console.log`的區別
```javascript
function greeting(name) {
// say a friendly hi
console.log("Hello world! This is" + name) // 印出Hello world! This istai
return `name: ${name}` //回傳 name: tai
}
let ret = greeting('tai')
console.log(ret);
```
跟`ruby`的語法不同,如果沒有`return`,就不會有回傳值
```javascript
function greeting1(name) {
console.log("Hello world! This is" + name)`
}
let result = greeting1("Mary")
console.log(result) // undefined
```
ruby
```ruby
def bar(x)
if(x < 100) {
return 100
} else {
300 # return 300
}
end
```
呼叫函式`call`, `invoke`時一定要加括弧 `foo()`
```javascript
function greeting2(name) {
// say a friendly hi
console.log("Hello world! This is" + name)
console.log("function ends") // 偵測到無法執行的程式碼
return // 自以為有分號,結果變成沒有回傳值
`name: ${name}`
}
let result2 = greeting2("Mary")
console.log(result2) // undefined
```
## method 和 function 有什麼不同?
Ruby: 如果一個function隸屬於一個物件,就是一個method
依照ruby的method規則,以下會出錯
```ruby
p [1, 2, 3, 4, 5, 6].map def i
i + 1
end
```
但是在JS裡,函式是自由的
以下是沒有名字的函式
```javascript
let res8 = [1, 2, 3, 4, 5].map(function(i){ return i + 1})
console.log(res8) #=> [ 2, 3, 4, 5, 6 ]
```
把函式提出來 (JS函式的good part)
```javascript
function add1(i){ return i + 1}
let res8 = [1, 2, 3, 4, 5].map(add1)
console.log(res8)
```
# `==` 與 `===`
`==` 會自動幫忙轉型
比較時,盡量使用嚴格比較`===`
```javascript
let numberOne = 1
let stringOne = "1"
console.log(numberOne == stringOne) // true console.log(numberOne === stringOne) // false
```
(桃紅色的區域會發生很多奇怪的事!)

# if-else
計算車資
```javascript
let cartTotal = 1000;
let ratio;
function getRatio(total) {
if(total > 1000) {
return 0.8;
} else if (total > 500) {
return 0.9;
} else {
return 1;
}
}
console.log(cartTotal * getRatio(cartTotal))
```
# For迴圈
```javascript
let array = [1, 2, 3, 4, 5, 6];
let res50 = [0, 0, ...array, 7, 8, 9]
res50[0] = 100;
// 彈性,瑣碎:開頭可以調整,跳的走也可以 eg i +=2
for(var i = 0; i < res50.length; i ++) {
let result = res50[i] + 1;
console.log('I got a number: ', result) // => I got a number: 101
}
console.log(i) // => 印出11, 最後的檢查會再做一次,但是發現條件不會符合
```
console
```
I got a number: 101
I got a number: 1
I got a number: 2
I got a number: 3
I got a number: 4
I got a number: 5
I got a number: 6
I got a number: 7
I got a number: 8
I got a number: 9
I got a number: 10
11
```
像ruby版本寫法的迴圈
```javascript
for(let x of res50){
console.log(x) // 走的過程不會去亂動陣列本身
}
```
# case 條件判斷
```javascript
let gender = 'F', title;
switch(gender) {
case 'M':
title = 'Mr.';
break;
case 'F':
title = 'Ms.';
break;
default:
title = '';
}
console.log(title);
```
# 集合 Collection
1. `[]`
```javascript
let array = [1, 2, 3, 4, 5, 6];
let res2 = array;
console.log(res2); // => [ 1, 2, 3, 4, 5, 6 ]
let res5 = array.pop();
console.log(res5); // => 6
let res8 = array.slice(1,4);
console.log(res8); // => [2, 3, 4]
// immutible: 不可被修改的
// push pop slice 這些函式會動到陣列本身
// functional派:不要動到array本身
let res12 = [...array, 7 ,8 ,9]
console.log(res12); // => [[ 1, 2, 3, 4, 5, 7, 8, 9]
```
2. `{}`:鍵值對:像是字典的東西
值可以重複,鍵不行
在JavaScript叫做Object
Object的兩種用法:
1. 查表
2. 表達物件的狀態
```javascript
let areaCode = { // 查表
'us': '01',
'tw': '886',
'hk': '86',
}
let student = { // 表達物件狀態
'name': 'John',
'age': 18,
'gender': 'M',
'favorite': ['music', 'eat'],
}
```
```javascript
let areaCode = {
'us': '01',
'tw': '886',
'hk': '86'
}
let country = 'hk'
console.log(areaCode[country]) // => 86
```
取值與設值的規則:
如果是為了拿到特定的結果,使用`[]`,其他時候用`.`
```javascript
let areaCode = {
'us': '01',
'tw': '886',
'hk': '86'
}
let student = {
'name': 'John',
'age': 18,
'gender': 'M',
'favorite': ['music', 'eat']
}
let country = 'hk'
console.log(areaCode[country]) //=> 為了取出`86`這個值
console.log(student.age)
```
# 手動表現出變數提升
```javascript
function baz(x){
let amount, total, qty; //先寫出來放著
//do something
amount = 100;
}
```
# 讓整個函數提升
用`function baz(x)`這種方式定義`function`
把不重要的小函式藏在底下
```javascript
baz(1000)
function baz(x){
var amount, total, qty;
//do something
amount = 100;
console.log(amount + x)
}
```
# 另外兩種定義函式的方式
1. function指定給變數
```javascript
putInPot('beef') // beef in pot
function putInPot(x) {
console.log(`${x} in pot`)
}
// function指定給變數
let lalala = function (x) {
console.log(`${x} in pot`)
}
```
2. 箭頭函式 (ES6)
```javascript
let addOne = function(x) {return x + 1}
let addOne2 = x => x + 1 // 前面是參數,後面是回傳值
// 第一步:把function拿掉
let addOne = (x) => {
return x + 1
}
// 第二步:把{}和return拿掉
let addOne = (x) => x + 1
// 第三步:如果參數只有一個,()可以拿掉
let addOne = x => x + 1
```
如果參數有兩個,不能走第三步(不能把括弧拿掉)
```javascript
let addOne = (x, y) => x + y + 1
```
# 高階函式
處理函式的函式
原始的寫法長這樣:
```javascript
putInPot('beef');
putInPot('water');
console.log('I make dinner with beef')
boomboom('chicken')
boomboom('coconut');
console.log('I make dinner with chicken')
function putInPot(x) {
console.log(`${x} in pot`)
}
function boomboom(x) {
console.log(`cooking ${x}`)
}
```
```javascript
beef in pot
water in pot
I make dinner with beef
cooking chicken
cooking coconut
I make dinner with chicken
```
把pattern找出來
```javascript
// cook('第一個食材'、'第二個食材','callback function': 這邊人家會透過參數丟一個函式進來,自己決定什麼時候要呼叫
cook('beef', 'water', putInPot);
cook('chicken', 'coconut', boomboom);
// 高階函式:處理函式的函式
function cook(i1, i2, f) {
f(i1)
f(i2)
console.log(`I make dinner with ${i1}`)
}
```
```javascript
cook('beef',
'water',
x => console.log(`${x} in pot`))
cook('beef',
'water',
x => console.log(`cooking ${x}`))
// 函數是自由的,console log也是一個function,所以可以提到外面來
let pp = console.log
cook('beef',
'water',
x => pp(`${x} in pot`))
cook('beef',
'water',
x => pp(`cooking ${x}`))
```
下堂課前情提要:
用函式產生函式:呼叫高階函式的時候,直接把函式定義在後面
```
[1, 2, 3, 4, 5].map(x => x + 1)
[1, 2, 3, 4, 5].select(x => x > 3)
[1, 2, 3, 4, 5].reduce(x, acc => x + acc)
let curriedAdd = x => y => z => x + y + z
```
eg. 雖然不知道什麼時候會發生,但某個事件觸發的時候,會呼叫後面的函式
```htmlmixed
<body>
<button id="btn">Don't Click</button>
<script>
document
.querySelector('#btn')
.addEventListener('click', () => {
for (let i = 0; i < 5; i++) {
alert('Hey!!!! WTF')
}
alert('OK..')
})
</script>
</body>
```