--- 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 ``` ![](https://i.imgur.com/jtxUwLf.png) ![](https://i.imgur.com/1tD9GOy.png) ![](https://i.imgur.com/JHOgCdI.png) 為了知道按下`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 ![](https://i.imgur.com/gmt0oLD.png) `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() // 好吃 ```