JavaScript(2023/10/16-2023/10/20) === > JS / ES6 EcmaScript(ES) 規範 JS 一種ES # 變數常數資料型態 ## 宣告變數(variable) >不能數字開頭、不能用保留字、變數本身沒有型態 ### let * 有變數提升嗎? * JS兩階段運行,let 不會幫忙初始化 TDZ所以感覺像是沒有變數提升 但其實有 * Scope小,若在{...}中宣告,即僅能存在{...}中,不易污染 ### var * 有變數提升 * Scope大,容易污染 * function scope是唯一能夠關住var的 ### const * 又稱常數 * 常數值不能改 * 陣列裡的某項可以改 * 因為指向陣列,並沒有改變 ### var v.s. let ![](https://hackmd.io/_uploads/Sy5rYAnb6.png) ### 宣告準則(建議) 1. const 2. let 3. var ### 範例: ```javascript= if (true) { var a = 1 let b = 1 } console.log(a); console.log(b); /*結果: a = 1 b is not defined(因為let會被{...}關住)*/ ``` ## 變數提升(variable hoisting) ### Creation Phase * 註冊名稱 * `var a = 1` -> 此時 a = undefined ### Execution Phase * 初始化 * 賦值 & 執行函數 * `var a = 1` ->此時 a = 1 ### 範例1 ```javascript= console.log(a); var a = 1; /* 結果為undefined */ ``` ### 範例2 ```javascript= console.log(a); let a = 2 /* 結果為Cannot access 'a' before initialization */ ``` ## 全域變數 * 未宣告的東西會放在全域變數 * var 的東西也會放在全域變數 * 範例: ```javascript= a = 100 console.log(a); /*結果為100,a被放在全域變數裡*/ ``` ## 常數補充 >常數(constant)又稱定數,是指一個數值固定不變的數,例如圓周率,與之相反的是變數。 * const一定要初始化(賦值) * const Array內容可以變長,改變,但不能重複定義 ### 範例1: ```JavaScript= const a; console.log(a); /* 結果:Missing initializer in const declaration */ ``` ### 範例2: ```JavaScript= const list = ["a","b","c"] list = ["a","b","c"] const list = 1 list = 2 /* 結果:yntaxError: Identifier 'list' has already been declared */ // const 不能 re-assign // list[0] = "x" ``` ### 範例3: ```JavaScript= const list = ["a","b","c"] list.push("d"); console.log(list); /* 結果:[ 'a', 'b', 'c', 'd' ]*/ ``` ## 資料型態 ### 原始型別 * Number * String * Boolean * Null * Undefined * Symbol ### 物件型別 * Array * Function * Object ### 判斷資料型別 ```javascript= console.log(typeof(n)) ``` ## 補充說明 * 先得到a值 再幫忙+1: ```javascript a = a + 1 a += 1 ``` * 先增加1再幫忙印出來: ```javascript ++a ``` ## 錯誤 :::info * SyntaxError -> 語法錯誤 * ReferenceError: b is not defined -> 未宣告 * annot access 'a' before initialization -> 未初始化 * Missing initializer in const declaration -> 常數未賦值 ::: --- # 流程控制 ## 判斷 ```JS= let age = 13 if (age >= 18) { console.log("已成年") } else if (age >= 12 && age < 18) { console.log("青少年") } else { console.log("小朋友") } ``` ## 三元 ```JS= age >= 18 ? console.log("已成年") : console.log("未成年") ``` ## switch ```javascript!= let gender = 2 switch (gender) { case 1: console.log("男"); break case 2: console.log("女"); break default: console.log("no"); break } ``` ```javascript!= let year = 2024 if (year % 4 == 0 && year % 100 !== 0 || year % 400 == 0 ) { console.log("閏年"); } else { console.log("平年"); } ``` ## 代表False * false * undefined * null * 0 * NaN * NaN不等於任何人,包括他自己 * Not a Number , type = number * NaN === NaN ```javascript!= let a = NaN; if (isNaN(a)) { console.log("is NaN"); } else { console.log("not NaN"); } /* 結果 is NaN */ ``` # 內建方法 * Boolean() => 傳出true or false ## 基本符號 * == 等於 * !== 不等於 * = assign * || or * && and * not * ** 次方 ## 迴圈 ### for ```javascript!= for(var i = 0; i < 5; i++){ console.log(i); } ``` 可使用`break` & `continue` #### continue: 跳過這回合 ```javascript= // 印出 2,4,6,8,10 for (var i = 1; i <= 10; i++) { if (i % 2 == 1) { continue; } console.log(i); } ``` ### while >不知道要跑多久,跑到沒有為止 ```javascript!= let a = 0 while (a < 10) { console.log(a); a ++ } ``` ## 範例 ```javascript= /*聖誕樹,使用者輸入幾層,就會出現幾層聖誕樹*/ function createTree(layouts) { for (let n = 1; n <= layouts; n++) { console.log(" ".repeat(layouts - n) + "*".repeat(n * 2 - 1)); } console.log(" ".repeat(layouts - 1) + "*"); console.log(" ".repeat(layouts - 1) + "*"); } createTree(3); // 輸出: * *** ***** * * ``` ```javascript= /* 1加到100 */ let sum = 0; for (let i = 1; i <= 100; i++) { sum = sum + i; } console.log(sum); // 輸出:5050 ``` # 函數(Function) >將複雜的流程用一個名字包起來 >輸入值&輸出值之間的關係 >函數是數學描述對應關係的一種特殊集合 >一等公民(我們都一樣)怎麼處理數字就怎麼處理函數 ## 基本介紹 ### 參數(parameter),名稱(name),引數(argument) ```javascript= function name(x) { console.log(3 * x + 2); } name(3); //輸出 11 // name(x) => x為參數 // name(3) => 3為引數 ``` ## 參數預設值 ```javascript!= //預設值 y = 0 function add(x, y = 0) { console.log(x + y); } add(1, 2); // 3 add(2); // 2 add(3); // 3 ``` ### 函數兩階段運作 * function declaration在第一階段時便已完成 1a + 1b +2 * function declaration能將呼叫函數放在任何地方 * 如果在箭頭、匿名函式裡,將呼叫函示放在不對的地方的錯誤訊息:const => 未初始化 var => 不是個function #### 範例: ```javascript!= console.log(add_2(1)); function add_2(m) { return m + 3; } // 4 ``` ## 不同函式的寫法 ### 匿名函數 沒有名字 ```javascript!= const add_1 = function (m) { return m + 1; }; console.log(add_1(123)); //124 ``` ### 具名函數 ```javascript!= function add_2(m) { return m + 3; } console.log(add_2(1)); //4 ``` ### 箭頭函數 ```javascript!= const add_3 = (m) => { return m + 2; }; console.log(add_3(1)); //3 ``` ### 箭頭函數精簡版 ```javascript!= const add_4 = (m) => m + 4; console.log(add_4(1)); //5 ``` ### function expression ```javascript!= const add = (m) => { return m + 2; }; ``` ### function declaration ```javascript!= function add(m) { return m + 3; } ``` ## 回傳值 * console.log(x)沒有回傳值,使用return才有回傳值 * console.log(x)為印出值 * 若在REPL環境下,可以印出結果 * 沒有指定 就預設回傳undefined * return後,就不會動 * 所有函數都有回傳,沒有return也會得到undefined ### 回傳值範例 ```javascript!= function add(x, y) { return x + y; } console.log(add(2, 3)); ``` ```javascript= //是否成年 function isAdult(age) { return age >= 18; } console.log(isAdult(20)); //true console.log(isAdult(12)); //false ``` ### Early return >設計多條件判斷的邏輯時,可使用Early return 技巧,讓程式盡可能提早結束,避免去執行到不該執行的部份 ```javascript= function add(x, y) { if (y == undefined) { return x; } return x + y; } console.log(add(2, 3)); console.log(add(2)); ``` ### REPL >「讀取-求值-輸出」循環(英語:Read-Eval-Print Loop,簡稱REPL),也被稱做交互式頂層構件(英語:interactive toplevel)。 -Wiki ## 高階函數 函數包函數就是高階函數 ```javascript= function hello(x) { if (typeof x == "function") { x(); } else { console.log(x); } } function a() { console.log(`I am function`); } hello(1); //1 hello(a); //I am function //如果打成hello(a())為需要秀出a執行後的結果 //會印出 aaaaa & undefined ``` ## 範例 ```javascript= // BMI計算機 function BmiCalculator(height, weight) { let h = height / 100 let bmi = weight / (h^2) result = bmi.toFixed(2) console.log(result) } BmiCalculator(height, weight) ``` ```javascrip= // 閏年 function isLeapYear(year) { return (year % 4 ===0 && year %100 !== 0) || (year % 400 ===0) } console.log(isLeapYear(2020)); ``` ```javascript= //奇數還是偶數? function evenOrOdd(n) { if (n % 2 == 0) { return "Even"; } return "Odd"; } console.log(evenOrOdd(-1)); //Even ``` ```javascript= // 加稅前的價格 const VAT = 0.15; function excludingVatPrice(price) { if (price == null) { return -1; } const result = price / (1 + VAT); return Number(result.toFixed(2)); } console.log(excludingVatPrice(230)); //toFixed會變成字串,所以要用Number轉換 ``` ```javascript= //加稅前的價格 解法二 const VAT = 0.15; function round(num, digit) { return Number(num.toFixed(digit)); } function excludingVatPrice(price) { if (price == null) { return -1; } const result = price / (1 + VAT); return round(result, 2); } console.log(excludingVatPrice(230)); ``` ```javascript= //取小數點後幾位 function round(num, digit) { const ratio = 10 ** digit; return Math.round(num * ratio) / ratio; } console.log(round(2.333333, 2)); // 2.33 console.log(round(2.333733, 3)); // 2.334 ``` ## 補充說明 * JavaScript會往外找宣告變數 * undefined = NaN ### 補充1 ```javascript= console.log(1 < 2 < 3); // true // 1 < 2 = true // true和3比較時,true會變成1 // 1 < 3 // 答案為true console.log(3 > 2 > 1); //false // 3 > 2 = true // true和1比較時,true會變成1 // 1不>1 //答案為false ``` # 陣列 ```javascript= let heros = ["a","b",123,456] ``` ## 二維陣列 ## 取得第N顆元素 ```javascript!= let hero =["1","3","5","c"] console.log(hero[2]); // 印出 5 ``` ## 最後一個元素索引值 ```javascript!= console.log(hero[hero.length -1]) ``` ## 增加元素 #### Array.push("") 從陣列最後面增加 ```javascript!= let heroes = ["A", "B", "C", "D"]; heroes.push("E"); console.log(heroes); //印出[ 'A', 'B', 'C', 'D', 'E' ] ``` #### Array.unshift("") 從陣列的最前面增加 ```javascript!= let heroes = ["A", "B", "C", "D"]; heroes.unshift("E"); console.log(heroes); //印出['E', 'A', 'B', 'C', 'D' ] ``` ### Array.prototype.splice(開始index,砍掉幾個,塞入) ```javascript= const list = [1, 2, 3, 4]; list.splice(2, 2, "a"); //star:2 ,要砍掉多少個,填充物"a" console.log(list);//[1,2,'a',3,4] ``` ### 針對陣列調整 ```javascript= const list = [1, 2, 3, 4]; list.length = 0; console.log(list); //[] ``` ```javascript= const list = [1, 2, 3, 4]; list.length = 2; console.log(list);//2 ``` ```javascript= const list = [1, 2, 3, 4]; list[5] = 10; console.log(list); //[ 1, 2, 3, 4, <1 empty item>, 10 ] ``` ## 減少元素 #### Array.pop()從陣列最後面減少 ```javascript!= let heroes = ["A", "B", "C", "D"]; heroes.pop(); console.log(heroes); //印出 [ 'A', 'B', 'C' ] ``` #### Array.shift() 從陣列最前面減少 ```javascript!= let heroes = ["A", "B", "C", "D"]; heroes.shift("A"); console.log(heroes); //印出[ 'B', 'C', 'D' ] ```` ## 印出被取的元素 ```javascript!= ``` ## 替換 #### heroes[0] = "Z" ```JavaScript!= let heroes = ["A", "B", "C", "D"]; heroes[0] = "Z"; console.log(heroes); //印出[ 'Z', 'B', 'C', 'D' ] ``` ## 組裝 #### array1.concat(array2) ```JavaScript!= let Aheroes = ["A", "B", "C"]; let Bheroes = ["D", "E", "F"]; Cheroes = Aheroes.concat(Bheroes); console.log(Cheroes); //印出[ 'A', 'B', 'C', 'D', 'E', 'F' ] ``` ## 陣列位置 ### Array.prototype.indexOf() 找不到值時拋出-1 ```javascript= let score = [2, 4, 8, 9, 10]; console.log(score.indexOf(2)); //0 console.log(score.indexOf(10)); //4 console.log(score.indexOf(100)); // -1 找不到值時 console.log(score.indexOf(-5)); // -1 找不到值時 ``` ### Array.prototype.includes() 僅顯示true or false ```javascript= let score = [2, 4, 8, 9, 10]; console.log(score.includes(2)); // true console.log(score.includes(10)); // true console.log(score.includes(100)); // false console.log(score.includes(-5)); // false ``` ## 印出陣列裡的值 ### 用for迴圈 ```javascript= let score = [2, 4, 8]; for (var i = 0; i < score.length; i++) { console.log(score[i]); } //2 //4 //8 ``` ### 用forEach 把裡面東西一個個丟出來 遍歷 迭代 iteration 每一步再走會把東西丟出來 forEach ```javascript= //印出陣列裡的值 forEach const array1 = ["a", "b", "c"]; array1.forEach((element) => console.log(element)); //a //b //c ``` ```javascript= const list = [1, 2, 3]; list.forEach(function (a) { console.log(a * 2 + 1); }); // 3 // 5 // 7 ``` ```javascript= //新陣列 const list = [1, 2, 3, 4, 5]; const result = []; list.forEach(function (a) { result.push(2 * a); }); console.log(result); console.log(list); ``` ## 找出特定陣列 ### 使用Array.propetery.find() #### 只回傳符合條件的第一個 ```javascript= let heroes = ["AA", "BBBB", "C", "DD"]; let user = heroes.find(function (n) { return n.length >= 4; }); console.log(user); //BBBB ``` #### 箭頭式 ```javascript= let list = [1, 3, 5, 8, 9]; let result = list.find((n) => n % 2 == 0); console.log(result); ``` ## reverse() 反轉 ```javascript var a = ["one", "two", "three"]; var reversed = a.reverse(); console.log(a); // ['three', 'two', 'one'] console.log(reversed); // ['three', 'two', 'one'] ``` ## map 對裡面每個元素做某件事情,最後做出新的陣列 ### 陣列內的數字放大五倍 ```javascript= let heroes = ["A", "B", "C", "D"]; let result = heroes.map((h) => { return h.repeat(5); }); console.log(result); //[ 'AAAAA', 'BBBBB', 'CCCCC', 'DDDDD' ] ``` ### 每個英雄前面加上超級 ```javascript=! let heroes = ["孫悟空", "魯夫", "宇智波佐助"]; const superHero = heroes.map(function (hero) { return "超級" + hero; }); console.log(superHero); // [ '超級孫悟空', '超級魯夫', '超級宇智波佐助' ] ``` ## Filter >在陣列裡做判斷,符合條件再收起來 ```javascript=! //判斷名字只有兩個以上 let heroes = ["AAA", "B", "CC", "DDD"]; let result = heroes.filter((n) => { return n.length >= 2; }); console.log(result); //[ 'AAA', 'CC', 'DDD' ] ``` ## 陣列加總 ```javascript= 陣列簡單迴圈 let score = [2, 4, 8, 9, 10]; let total = 0; for (i = 0; i < score.length; i++) { total = total + score[i]; } console.log(total); ``` ## 運用reduce加總 * redece接兩個參數&一個起始值 * acc = 累加值 cv = 每次加的值 * 如果沒有預設值,會拿元素第一個當預設值,從第二顆開始跑 * acc = 上一輪丟出的cv ```javascript= let score = [2, 4, 8, 9, 10]; let result = score.reduce((acc, cv) => { return acc + cv; }, 0); console.log(result); ``` ### 連續技 * 把function拉出來,再簡化 ```javascript= const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const result = arr.filter(biggerArr).map(doubleArr); console.log(result); function biggerArr(n) { return n >= 8; } function doubleArr(n) { return n * 2; } ``` * 挑出偶數加總 ```javascript= const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const result = arr.filter(even).reduce(sum); console.log(result); function even(n) { return n % 2 == 0; } function sum(x, y) { return x + y; } ``` * 把複雜的字串,整理成只有數字的字串 * type of不是function,是關鍵字 ```javascript= const list = [1, "a", 3, 5, undefined, [], true]; const result = list.filter((n) => typeof n === "number"); console.log(result); ``` #題目觀摩 ```javascript= [1,2,3,4].reduce((x,y) => x+y) ``` --- # 物件 * 物件 =屬性(名詞) + 行為(動詞) * 陣列就像用數字當索引值的物件 ## 建立物件 ```javascript= let buibui = { name: "阿肥", age: 6, attack: function () { console.log("喵喵喵"); }, }; console.log(buibui.age); //6 console.log(buibui.name); //阿肥 console.log(buibui["name"]);//阿肥 buibui.attack();//喵喵喵 ``` ## 增加物件屬性 callback ```javascript= let buibui = { name: "阿肥", age: 6, attack: function () { console.log("喵喵喵"); }, }; buibui.color = "紅色"; //<=增加屬性用這個 console.log(buibui.color); //"紅色" ``` ## 刪除物件屬性 delete ```javascript= let buibui = { name: "阿肥", age: 6, attack: function () { console.log("喵喵喵"); }, }; buibui.color = "紅色"; delete buibui.name; console.log(buibui); //{ age: 6, attack: [Function: attack], color: '紅色' } ``` ### 範例1: ```javascript= const a = { nn: 123, // nn => key // 123 => value cc: 456, }; console.log(a["nn"]); console.log(a.nn);/* 建議*/ /* 結果123 123 */ ```