---
title: Astro課程 0813 - JavaScript (Day2)
tags: astro, javascript
---
# JavaScript 函式的補充
## 無論如何會接收參數或環境變數
ruby 會檢查參數數量
```
def foo(x, y, z)
end
# foo(1, 2, 3)
foo(1, 2)
js02.rb:1:in `foo': wrong number of arguments (given 2, expected 3) (ArgumentError)
```
### js: 完全不檢查參數數量
給多的就當作沒看見
```
function foo(x, y, z) {
console.log("x: ", x);
console.log("y: ", y);
console.log("z: ", z);
}
// foo(1, 2, 3)
foo(1, 2, 3, 4, 5, 6)
```
result
```
x: 1
y: 2
z: 3
```
### 少給的部分是undefined
```
function foo(x, y, z) {
console.log("x: ", x);
console.log("y: ", y);
console.log("z: ", z);
}
// foo(1, 2, 3)
foo(1, 2)
```
```
x: 1
y: 2
z: undefined
```



為了知道按下`btn`按鈕時,發生什麼事,會帶`event`進來
```
function clickHandler(event) {
}
document.getElementById('btn').addEventListender('click', clickHandler);
clickHandler(event)
```
Eg. 輸入帳號密碼
```
document.getElementById('btn').addEventListender('keydown', function(evt) {
console.log(evt)
});
```
跟鍵盤有關的事件
`keydown`: 連續按下不放
`keypress`: 按下去再放開
`keyup`
Eg. 輸入帳號,按下enter才出現輸入密碼欄位
```
$("#user_account").keydown(function (event) {
if (event.which == 13 && $(this).val().length > 0){
if ($('#user_account').val().toLowerCase() == 'new'){
window.location.href = '/users/sign_up';
} else {
$("#p_password").show();
$("#user_password").focus();
}
} else {
$("#p_password").hide();
}
});
```
## closure 閉包
[Ref](https://cythilya.github.io/2018/10/22/closure/)
[MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Closures)
ruby
```
# This is RUBY!!!!
variable = 1
def foo(x, y, z)
p variable
end
foo(1, 2, 3)
```
ruby拿不到外面的變數
js 拿得到
```
let variable = 100;
function bar() {
console.log(variable)
}
bar() // 100
```
但是變數名稱剛好一樣的話,裡面的會遮住外面的
```
let variable = 100;
function bar() {
let variable = 999;
console.log(variable)
}
bar() // 999
```
##
ruby
```
ary = [1, 2, 3, 4, 5]
# first = ary[0]
# second = ary[1]
# third = ary[2]
first, second, third = ary
p first
p third
```
## Destructive assignment
[解構賦值- JavaScript | MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
js設計好的地方:把結構拆到變數裡去
```
let ary = [1, 2, 3, 4, 5];
let [first, second, third] = ary;
console.log(third) // 3
```
```
let [head, ...tails] = ary;
console.log(head); // 1
console.log(tails); // [ 2, 3, 4, 5 ]
```
(但是ruby沒有設計hash的Destructive assignment)
js 的object
```
let student = {name: 'john', age: 13, gender: 'M'};
// let studentName = student.name;
// let studentAge = student.age;
let {name: studentName, age: studentAge} = student;
// 右邊是整包資料
//let {name: studentName, age: studentAge} = {name: 'john', age: 13, gender: 'M'};
console.log(studentName); // john
console.log(studentAge); // 13
```
語法糖
如果變數與值名稱一樣,冒號以及之後的東西可以省略
```
//let {name: name, age: age} = student;
let {name, age} = student;
console.log(name);
console.log(age);
```
pattern match 是destructive assignment的進階版
(又可以給值、又可以比對)
進階版
```
let student = {name: 'john', age: 13, gender: 'M'};
function baz({name, gender}) {
console.log(name); // john
console.log(gender); // M
}
// let student = {name: 'john', age: 13, gender: 'M'};
baz(student)
```
實務上的應用: 把`{target: {keyCode}}`拿出來用(剝洋蔥剝出自己要的部分)
```
document.getElementById('btn')
.addEventListender('keydown', function({target: {keyCode}}) {
console.log(keyCode)
// console.log(evt)
});
```
## 範例
```javascript
<body>
<input type="text" name="name" id="name" class="inputCol">
<input type="password" name="pw" id="password" class= "inputCol">
<button id="btn">Login</button>
<script>
document.querySelector('inputCol').addEventListener('keypress', event =>{
console.log('event');
})
document.querySelector('#btn').addEventListener('click',()=>{
alert('login!!!');
})
</script>
</body>
```
## 按下enter,跳到password
先綁事件,查`enter`的keycode
按下1, 然後enter

`srcElement`,可以調到自己的id
`focus` 關注的地方
## 輸入完帳號、密碼後,才可以enter送出
```javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" name="name" id="name" class="inputCol">
<input type="password" name="pw" id="password" class="inputCol">
<button id="btn">Login</button>
<script>
const ENTER = 13;
for(let el of document.querySelectorAll('.inputCol')) {
el.addEventListener('keypress', (event) => {
let {keyCode, srcElement} = event;
if (keyCode === ENTER) {
checkInputAndLogin(srcElement.id);
}
})
}
function checkInputAndLogin(srcElementId) {
if (srcElementId === 'name') {
document.getElementById('password').focus();
return;
}
if (srcElementId !== 'password') { return; }
let nameVal = document.getElementById('name').value;
let pwVal = document.getElementById('password').value;
if (nameVal && pwVal) {
document.getElementById('btn').click();
}
}
document.querySelector('#btn').addEventListener('click', () => {
alert('login!!!!')
})
</script>
</body>
</html>
```
## 陣列的屬性與方法
`.fruits.length` => 屬性,沒有括號
`.fruits.join()` => 方法
### indexOf()
```javascript
let names = ['apple', 'banana', 'cherry'];
let joinedNames = names.join('\n');
console.log(joinedNames);
let indexOfCherry = names.indexOf('cherry'); // 2
console.log(indexOfCherry);
let indexOfCherry = names.indexOf('water');
// -1 無論如何回傳都是數字,不用再做其他的判斷( nul or undifined)
console.log(indexOfCherry);
```
### concat()
不會改變原來的陣列
```javascript
let names = ['apple', 'banana', 'cherry'];
let fruits1 = ['watermelon', 'pear']
let allFruits = names.concat(fruits1);
console.log(allFruits);
console.log(names);
console.log(fruits1);
```
## FIFO (queue) vs LIFO (stack)
frutis.pop()
fruits.shift()
fruits.push('pear')
fruits.unshift('grape')
## 迭代
### for of
[for...of](https://devdocs.io/javascript/statements/for...of)
很像array但不是array
這些資料撈出來有順序,但是沒有辦法用array的其他方法
```
let iterable = 'boo';
for (let value of iterable) {
console.log(value);
}
// "b"
// "o"
// "o"
```
## 鍵值對
## set
set和 array的差別 => 裡面的值不能重複
## Turple (元組)
其他語言(如python)內建
優點: 省記憶體
```javascript
let priceByCountry = {
'tw': 300,
'us': 10.2,
'jp': 1250,
}
// 如何換成array?
// Object.entries
let result = Object.entries(priceByCountry)
console.log(result)
//[ [ 'tw', 300 ], [ 'us', 10.2 ], [ 'jp', 1250 ] ]
```
```javascript
let result = Object.entries(priceByCountry)
.map(tpl => [tpl[0], tpl[1] * 1.05])
// object 轉成entries
let newPrice = Object.fromEntries(result)
console.log(newPrice)
// { tw: 315, us: 10.709999999999999, jp: 1312.5 }
```
# 其他不同的資料結構
```
let cat = {
name: 'mimi',
age: 3,
eat: function() { console.log('好吃!') }
}
// 當系統有大量物件,為了不要浪費記憶體,js會使用prototype
cat.eat() // 好吃
```