# 前端學習筆記 ## 1. 第一周-JavaScript: ### **一(方法、語法).** #### 常用內建函式or瀏覽器主控台使用語法 `consle.log() 印在主控台` `typeof 查看資料型態` `prompt() 跳窗輸入 alert() 跳窗顯示` `parseInt() 轉換為整數(Int)` `document 此語句於瀏覽器主控台輸入後可查看包含整個HTML的訊息(document.all 解析 DOM 的樹)` #### if...else... 結構 if(條件1){ (條件達成時執行敘述) }else if(條件2){ (條件達成時執行敘述) }else{ (都不符合以上條件時執行敘述) } #### switch...case...結構 switch (key) { case 1: (key == 1 執行敘述) break; case 2: (key == 2 執行敘述) break; default(都沒有的話): (都沒有的話執行的敘述) break; **一定要break; 因為條件達到時,執行完敘述必須跳離程式區塊** #### for 迴圈 for(var i = 初始值; i < 終止值; 遞增值++){ (需要迭代之內容) } #### while VS do...while // 前測式 while(跳離時條件){ (需迭代內容) } // 後測式 do{ (需迭代內容) }while(跳離時條件) #### Callback Function 回呼函數 function heyFunc(myFunction){ myFunction('Hi!!') } // 把 console.log()當作參數傳遞進myFunc() -> 使用console.log()去執行myFunc() heyFunc(console.log) // 把 alert() 當作參數傳遞進myFunc() -> 使用alert()去執行myFunc() heyFunc(alert) #### 匿名函式(Anonymous Function) function heyFunc(myFunction){ myFunction('Hi!!!'); } // 匿名函式 -> 以function heyFunc()為例 message:'Hi!!!' heyFunc(function(message){ console.log('message is:', message); }); #### 立即函式(Immediately Invoked Functions Expressions) (function(name){ var str = 'Hi, ' + name + ' !' console.log(str) })('Peter') // 函示沒有名稱,立即使用,function前後需有括弧將其保護,否則會出錯,函示結束處須加上參數 #### 物件宣告與使用 var dog = { name: 'Tracy', age: 20, bow: function(){ console.log('bow bow') } } // 呼叫 dog 的 name dog.name // key = name, value = 'Tracy' dog['name'] // 呼叫 dog 的 bow() dog.bow() // 增加color屬性 // 方法一 dog.color = 'white'; console.log(dog); // 方法二 dog['size'] = 'samll'; console.log(dog) // 增加bowbow() dog.bowbow = function(){ console.log('bow bow !!~~') } console.log(dog) #### 陣列(Array)的宣告及 pop()、push() 使用 // 宣告一個名為 arr 的陣列 var arr = ['apple', 'orange', 'banana'] // 用索引(index)取'apple' arr[0] console.log(arr[0]) // 把 arr 陣列最後一個元素回傳並刪除 arr.pop() console.log(arr) // 兩個元素(length = 2),因最後一個元素'banana'被回傳出來,並且刪除 // 將一個新的元素從 arr 陣列的尾處加入 arr.push('cat') // 加入'cat' console.log(arr) // 三個元素,因陣列尾處被加上'cat'元素(length = 3) #### 陣列的基本操作 var arr = [1, 2, 3, 4, 5, 6] console.log(arr) // 將第一個元素(arr[0])替換為 1000 arr[0] = 1000 console.log(arr) // 在陣列的第六個元素(arr[5])後插入一個新的元素 12345 arr[6] = 12345 console.log(arr) // 取得 arr 陣列的最後一個元素,不改變長度 arr[arr.length - 1] console.log(arr[arr.length - 1]) #### 陣列的基本操作- arr.indexOf()的使用 var arr = ['apple', 'orange', 'banana'] //indexOf() 取得元素的索引 console.log(arr.indexOf('orange')) #### 陣列的基本操作- 切片 slice()的使用 var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] arr.slice(2,4) // 'c' 、 'd' console.log(arr.slice(2,4)) // 含頭不含尾,即為 arr[2] ~ arr[3] #### 陣列進階方法- map() 對陣列內元素進行相同的操作 var dogs = ['Boy 1', 'Boy 2', 'Girl 1', 'Girl 2'] var result = dogs.map(function(dog){ // 將dogs裡的每個元素後面都加上'is good'字串 return dog + 'is good' }) console.log(result) #### 陣列進階方法-自己寫 map(),以for迴圈實作,效果同上(優先學習這邊!!,含有資料結構概念) var dogs = ['Boy 1', 'Boy 2', 'Girl 1', 'Girl 2'] function map2(dogs) { // dogs為放入map2()的參數,即為需要操作之對象 var result = [] for(var i = 0; i < dogs.length; i++){ // 使用for迴圈迭代dogs陣列 var str = dogs[i] + ' is good' console.log(str) result.push(str) } return result } var my_dogs = map2(dogs) #### 陣列進階方法-forEach(),以及迭代方法比較 // 宣告一個名為array1的陣列 const array1 = ['a', 'b', 'c'] // 以forEach()實作,不改變陣列內容 let forEachResult = array1.forEach(function(element) { console.log(element + ' is good') }) console.log(array1) // 以map()實作,會改變陣列內容 let mapResult = array1.map(function(element) { return element + ' is good' }) console.log(mapResult) // 以for迴圈實作,不改變陣列內容 for(var i = 0; i < array1.length; i++){ console.log(array1[i] + ' is good') } console.log(array1) #### filter()-過濾器 var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9] var new_arr = arr.filter(function(element) { // 回傳arr陣列中數字介於3~5的值,有等號,所以範圍是含頭含尾 return (element >= 3 && element<=5) }) console.log(new_arr) var arr1 = [ {name: 'Tom', age:20}, {name: 'Mary', age:30}, {name: 'Bill', age:50}, ] var new_arr1 = arr1.filter(function(person) { return person.age < 50 // 回傳年齡小於50的所有資料 return person.name === 'Tom' // 回傳名字等於Tom的所有資料 // 兩項return擇一進行實驗 }) console.log(new_arr1) #### find() VS filter() const arr1 = [5, 12, 12, 8, 130, 44] // 兩個12為實驗對象 let found = arr1.find(function(number) { return number === 12 }) console.log(found) // 只會有一個12,且是陣列中第一個12(arr1[1]) let filterFound = arr1.filter(function(number) { return number === 12 }) console.log(filterFound) //返回一個陣列[12, 12] #### Array.prototype實際操作 **(需詳細了解規則再去做需要之改寫)** Array.prototype.dog = 'bow' // 新增一個 Array.prototype 屬性 dog,值為 'bow' var arr = [] // 宣告一個空陣列以便呼叫dog屬性 console.log(arr.dog) #### reduce()實際操作 var numbers = [1, 3, 4, 5, 6, 7] // 以 forEach() 進行相同操作 var count = 0 // 同等於底下的sum,為暫存目前加總值 // 利用forEach() 對 numbers陣列的所有元素進行迭代 var all_num = numbers.forEach(function(num) { count += num }) console.log(count) // sum 為目前暫存加總值,current 為目前number中被操作的元素,即為陣列中的數字 var result = numbers.reduce(function(sum, current) { sum += current // 進行加總動作 return sum // 回傳給reduce函式,用意是告訴它現在操作(加總)到多少 }, 0) // 0為sum的預設值,通常這類計數器都由0開始 console.log(result) #### 宣告字元(var, let, const)作用域實作比較 // 作用域的改變 // var => function // let, const => {} // ex1: for 迴圈 - var 宣告 var i = 0; for(var i = 0; i < 10; i++){ console.log('迴圈跑第 ' + i + '次') } // 迴圈裡面的 i 汙染到外面的 i console.log(i) // 10 // ex2: for 迴圈 - let 宣告 let i = 0; for(let i = 0; i <10; i++){ console.log('迴圈跑第 ' + i + '次') } // 迴圈裡面的 i 沒有汙染到外面的 i,因為迴圈內的 i 作用域僅在迴圈內 console.log(i) // 0 // ex3: if...else... - var 宣告 var x = 1 if(x === 1){ var x = 5; }else{ var x = 10; } // 原理同上 console.log(x) // 5 // ex4: if...else... - let 宣告 let x = 1 if(x === 1){ let x = 5; }else{ let x = 10; } // 原理同上 console.log(x) // 1 // ex5: IIFE 立即函式 (function() { var x = 1; })(); let x = 3; // 原理同上 console.log(x); // ex6: const 常數變數宣告 const dog = 'Peter' // dog = 'Mary' // 主控台會拋錯,錯誤原因:不能再次對dog這個名稱進行操作 console.log(dog) // ex7: const 常數物件宣告(常數定義物件的時候其實是定義物件的位置) const person = { name: 'huang', age: 20, } person['name'] = 'Jason' console.log(person) // name: 'Jason', age: 20 // 物件內屬性仍可改變,但 person 物件已不能再次定義物件位置 #### 解構賦值(Destructuring Assignment) // 正常賦值 let a = 1 let b = 2 let c = 3 console.log(a, b, c) // 陣列解構賦值 let [a, b, c] = [1, 2, 3] console.log(a, b, c) // 物件解構賦值 let {a, b } = {a: 1111, b: 2222} // ES6(縮寫表示方式) let {a: a , b: b } = {a: 1111, b: 2222} // 完整表達式 console.log(a, b) // 1111 2222 #### iterator迭代協議 //字串實作 var myStr = 'hello' var iterator = myStr[Symbol.iterator]() console.log(iterator.next()) // h console.log(iterator.next()) // e console.log(iterator.next()) // l console.log(iterator.next()) // l console.log(iterator.next()) // 0 console.log(iterator.next()) // undefined // 陣列實作 var myArray = [1, 2, 3, 4, 5, 6, 7] var arrayiterator = myArray[Symbol.iterator]() console.log(arrayiterator.next()) // 1 console.log(arrayiterator.next()) // 2 console.log(arrayiterator.next()) // 3 console.log(arrayiterator.next()) // 4 console.log(arrayiterator.next()) // 5 console.log(arrayiterator.next()) // 6 console.log(arrayiterator.next()) // 7 console.log(arrayiterator.next()) // undefined #### for..of & for...in // for...of const array1 = ['a', 'b', 'c']; for(const element of array1) { console.log(element); } // for..in var object = { a: 1, b: 2, c: 3 }; function show_props(obj, objName) { // obj -> 放入函式的物件(object) var result = ""; for (var prop in obj) { // prop -> key值 // 因物件是dictonary形式(鍵值對) -> key: value,所以呼叫其屬性值需要以objname['keyname']的方式進行調用 result += objName + "." + prop + " = " + obj[prop] + "\n"; } return result; } alert( show_props(object, "object"), ); // object.a=1 object.b=2 object.c=3 #### 擴展運算子 Spread Operator // 使用在陣列上 let arr1 = [1, 2, 3, 4, 5] let arr2 = [6, 7, 8, 9] console.log(...arr1) // 依序將 arr1 中元素印出 // 以Math.min()為例 -> 找出最小值 var a = Math.min(arr1) console.log(a) //NaN -> Not a number ,因為此方法對象是一些值,而不是陣列 var b = Math.min(...arr1) // ...arr1 -> 1, 2, 3, 4, 5 console.log(b) // 陣列連接 let arr3 = [1, 2, 3, 4, 5] let arr4 = [5, 6, 7, 8, 9] var arr5 = [...arr3, ...arr4] // 等同於 var arr5 = arr3.concat(arr4) console.log(arr5) // 使用在物件上(須注意) let obj1 = { a: 1, b: 2, c: 3 } let obj2 = { c: 5, d: 6 } let result = {...obj1, ...obj2} console.log(result) // {a: 1, b: 2, c: 5, d: 6},會取代掉相同屬性 #### 箭頭函式(Arrow Function) const function1 = x => x + 1 console.log(function1(1)) // 2,沒有大括號,預設有回傳值 const function2 = x => {x + 1} // undefined,有大括號,沒有回傳值 console.log(function2(1)) // this 綁定的對象,不再是function本身 function greet() { let reply = `Hi, ${this.person}` console.log(reply) } var obj = { person: 'Bill' } greet.call(obj) // 1.一般函式 const obj1 = { a: 1, b: 2 } function myFunction1(){ // 以setTimeout()為例 console.log('output 1 ', this.a) // 1 setTimeout(function(){ // function是作用域的隔閡 console.log('output 2 ', this.a) // undefined }, 1000) } myFunction1.call(obj1) // 2.箭頭函式 const obj2 = { a: 1, b: 2 } function myFunction2(){ console.log('output 1 ', this.a) // 1 setTimeout( () => { // 箭頭函式不會有作用域的隔閡,因此不會影像到this console.log('output 2 ', this.a) // 1 }, 1000) } myFunction2.call(obj2) #### fetch(),執行非同步請求 -> Promise語句 const getNewDog = () =>{ // fetch 跟別人的伺服器拿東西。 // 支援promise,promise是一個方便的語法,可以用來執行一些非同步的環境。 fetch('https://dog.ceo/api/breeds/image/random') // 指定網站進行請求 // 依你的請求並透過.json()方法向目標網址要求資料 .then(response => response.json()) .then(json => { // json物件 console.log(json) dogImageDiv.innerHTML = `<img src='${json.message}'>` // 使用樣板字樣值將獲取到的message嵌入HTML碼 }) console.log('得到狗狗!') } ### **二(文字筆記).** JavaScript不分浮點數&整數 單、雙引號不得混用 ES6可以用`‵ ‵`符號進行宣告(1旁邊波浪符號鍵) 變數未指派值 = 未定義(undefined) 參與運算之符號 => 運算子/運算符 參與運算之數值 => 運算元 「 **=** 」 賦值運算子 「 **==** 」 比較運算子 「 **===** 」 (嚴謹)絕對比較運算子(多比較資料型態) => 常用 「 **&&** 」 AND 都真才真 「 **| |** 」 OR 都假才假 「 **| |=** 」 預設值 變數沒有值就給預設數值,有則直接返回該值 「 **!==** 」不等於 「 (運算式) ? (true執行敘述) : (false執行敘述) 」 -> 三元運算子 DRY => don't repeat yourself **表達式**(Expression) -> **會**回傳值 **陳述句**(Statement) -> **不會**回傳值 **一個Statement(陳述句)裡面可能會透過一些Expression(表達式)來得到一些值** 函式**陳述式**(Function Statement) -> 可以在函數**宣告前呼叫它** 函式**表達式**(Function Expression) -> **只能在函數宣告後進行呼叫** JavaScript **有變數提升 (Hoisting)** 的特性 在函式內使用**let**、 **var**...來保護變數不受影響 **window** -> **瀏覽器的根物件**,變數可用window來存取 ex: var y = 1,window.y -> 1 **node.js** 根物件 -> **global** **JavaScript** 是可以把函數做為參數傳遞;Java使用**Lambda**特性去實現相同效果;C 有 **function pointer** 的結構也可以達到同樣的效果 匿名函式使用時機 -> 當作參數傳遞進去的函式只需使用一次,即為在其他程式區塊不會使用它(函式),所以不用特別命名,稱為「匿名」 **console.log** 與 **console.log()** 之差異在於,前者為執行前,所以顯示其為函數;後者則是執行後(調用函數後),在括弧內輸入參數(想顯示的值),顯示結果為自定義參數,即為輸入值 **立即函式(Immediately Invoked Functions Expressions):** 1. 可以立即呼叫的函示表達式 2. 會回傳值(因有表達式之特性) 3. 使用函式表達式回傳後立即執行 使用let進行變數宣告前,**變數不得存取**,會出現 **Uncaught ReferenceError** 變數提升(Hoisting)詳細範例過程 -> 19.html **nodefined** -> 從未宣告 undefined(console.log(x),var x = 10,console.log(x) -> **第一個console.log(x)會等於undefined**,在賦予值之後,會**有值印出「第二個console.log(x)」**,即為有宣告,但未賦予值) -> 有宣告,未賦值 **let** -> 宣告前不得存取,宣告後不得再次宣告 **JavaScript中的物件:** 1. 用大括號宣告 2. 一個鍵(key)對應一個值(value) 3. 值又稱為屬性(attribute) 4. 物件內屬性可以是正常(基礎)型別(如:number, string, boolean, null, undefined, symbol「符號」)、陣列(array),也可以是function(函式) **陣列(Array)是一種資料結構:** 1. 物件是鍵值(key, value)的資料結構 2. 陣列是依照索引(index)排序的資料結構 **陣列詳細操作 網址**:https://www.oxxostudio.tw/articles/201908/js-array.html#array_shift **prototype** -> 可讓陣列這個資料結構有新的屬性或方法可以呼叫,ex:每一個陣列都會繼承這個 **map()** **(平常如無特殊需求不要隨意改寫Array.prototype)** MDN -> 有詳細教學 **function** 作為作用域是 **JavaScript** 的基本特性 **環境不符合** or **有使用第三方套件**的話,使用 **webpack** 來編譯 **find()** 與 **filter()** 的比較 -> 前者是返回符合條件的第一筆資料;後者則是返回符合條件的所有資料,資料類型可能會是陣列 **除了Chrome確定支援ES6,大部分瀏覽器不支援ES6,如有需要,可用babel將 ES6 -> ES5** **const(常數)定義後不會被改變** **迭代協議** -> https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Iteration_protocols **for...of(迭代可迭代的物件,需實作iterator),ES6新的標準** -> https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...of **for...in(直接迭代可列舉的屬性)** -> https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/for...in **擴展運算子 Spread Operator(...array):** 1. 快速將好幾個參數傳入function 2. 連接陣列 3. 連接物件(如果兩個或多個物件有相同屬性,須注意會被覆蓋) **文件物件模型(DOM, Document Object Model):** 1. HTML 須遵守 W3C 的規範 2. 遵守 W3C 的 HTML 可以被解析成 DOM 樹(tree) 3. 對應物件為 doucument -> window.document **HTML 樹狀(tree)結構** ![image](https://hackmd.io/_uploads/SySZ1Rqt6.png) **HTML 文件物件模型(DOM)結構** (每一個元素都是一個物件) ![image](https://hackmd.io/_uploads/BJR3JAct6.png) **應用程式編程介面(API, Application Programming Interface):** 1. A, Application:應用程式本身 2. P, Programming:透過編程行為產出與應用程式交談的程式 3. I, Interface:透過程式產生的介面,使人能與程式交流 **總結:透過寫程式的方式與應用程式溝通** DOM Document詳細操作 -> https://www.w3schools.com/js/js_htmldom_document.asp **瀏覽器物件模型(BOM, Browser Object Model):** 1. B, Browser:代表整個瀏覽器 2. O, Object:代表物件,即為瀏覽器的每個元素 3. M, Model: 代表模型,完整的瀏覽器結構所形成的模型 4. 對應物件為 window(根物件,不用特別區宣告,且接下來宣告的東西都會依附在『根物件』上面) window 樹狀結構圖: ![image](https://hackmd.io/_uploads/HyqxcAqK6.png) **以window根物件中的location API為例:** window.location.href -> 可以取得當前瀏覽網頁之網址 **以history API為例:** window.history.back() -> 回到上一個瀏覽頁面 window.history.go(1) -> 導向下一頁,輸入參數用來控制導向之頁面 window.history.go(-1) -> 回到上一頁 JavaScript是一個依賴根物件的語言 ## 2. 第二周: ### **一(方法、語法).** jQuery("h1") = $("h1") 找到h1標籤的位置 jQuery("p") = $("p") 找到p標籤的位置 $(".articles") 找到所有articles類的元素(在css中自己定義的) $("#container") 找到所有container容器的元素 $('#destinations li') 找出#destinations底下的所有<li>標籤 $(this).parent('.vacation') 找出這個標籤的父節點,括號內若增加參數,即為尋找這個標籤的父節點上的vacation類別(可能會返回很多個vacation類別) $(this).closest('.vacation') 透過遍歷DOM的方式來找到vacation類別的父節點,並可加以操作(解決上面的問題) .slideDown() 顯示 .slideUp() 隱藏 .slideToggle() 輪流觸發 .fadeIn() 淡入 .fadeOut() 淡出 .fadeToggle() 輪流觸發 .show() 顯示 // 用來處理display: none、display: block .hide() 隱藏 .addClass() 目標新增樣式,括弧內參數為要新增之css樣式 .removeClass() 目標移除樣式 .toggleClass() 目標可新增可移除樣式 1. 元素選擇器 // Html: <ul id="destinations"> <li>Rome</li> <li> <ul id="france"> <li>Paris</li> </ul> </li> <li class="promo">Rio</li> </ul> //script: <script> $(document).ready(function(){ $("#destinations > li"); // 選擇#destinations底下第一層<li>標籤 $(".promo, #france"); // 逗號可選擇多個元素 $("#destinations li:first") // 偽選擇器,#destinations底下第一個<li>標籤 }) </script> 2. 插入子節點 // Html: <li class="vacation" style=" list-style-type: none; margin-left: 200px;"> <h2>Hawaiian Vacation</h2> <button>Get Price</button> </li> // script: <script> $(document).ready(function(){ var price = $('<p>From $399.99</p>') // 宣告一個新的<p>標籤(節點) // $('.vacation').before(price) // vacation 類別的前面 // price.insertBefore($('.vacation')) // 同上 // $('.vacation').after(price) // vacation 類別的後面 // price.insertAfter($('.vacation')) // 同上 // $('.vacation').prepend(price) // vacation 類別中的第一個 // price.prependTo($('.vacation')) // 同上 // $('.vacation').append(price) // vacation 類別中的最後一個 // price.appendTo($('.vacation')) // 同上 // $('button').remove() // 移除button那個位置的節點 }) </script> 3. 監聽事件(滑鼠點擊) // Html: <li class="vacation" style=" list-style-type: none; margin-left: 200px;"> <h2>Hawaiian Vacation</h2> <button>Get Price</button> </li> //script: <script> $(document).ready(function(){ $('button').on('click', function() { // 監聽事件,滑鼠點擊 var price = $('<p>From $399.99</p>') $('.vacation').append(price) // vacation 類別中的最後一個 // price.appendTo($('.vacation')) $('.vacation').addClass('p1') $('button').remove() // 移除button那個位置的節點 }) }) </script> 4. this的用法 //Html: <h1>Vacation Page</h1> <div id="vacations"> <ul style="display: flex;"> <li class="vacation" style=" list-style-type: none; margin-left: 200px;"> <h2>Hawaiian Vacation</h2> <button>Get Price</button> </li> <li class="vacation" style=" list-style-type: none; margin-left: 200px;"> <h2>Orlando</h2> <button>Get Price</button> </li> <li class="vacation" style=" list-style-type: none; margin-left: 200px;"> <h2>Visit Japan</h2> <button>Get Price</button> </li> </ul> </div> // script <script> $(document).ready(function(){ $('button').on('click', function() { // 監聽事件,滑鼠點擊 var price = $('<p class="p1">From $399.99</p>') $(this).closest('.vacation').append(price) // 你點哪裡就作用哪裡$(this)。 $(this).remove() // 移除button那個位置的節點 }) }) </script> ### **二(文字筆記).** jQuery 可以做哪些事: 1. 找到HTML頁面中的元素 2. 改變HTML內容 3. 根據用戶的操作作出反饋 ex:按下按鈕 4. 在頁面中使用動畫效果 5. 與網頁交談 6. 如果不想刷新頁面而改變頁面內容,那就可以使用jQuery class -> "." id -> "#" data-tag -> HTML5的特性 滑鼠監聽事件種類: 1. click -> 單擊滑鼠 2. dblclick -> 雙擊滑鼠 3. focusin -> 4. focusout -> 5. mouseup -> 6. mousedown -> 7. mousemove -> 8. mouseout -> 9. mouseover -> 10. mouseleave -> 11. mouseenter -> 當滑鼠進入元素區域內,即可觸發 鍵盤監聽事件種類: 1. keypress 2. keydown 3. keyup -> 敲完一個鍵 表單監聽事件種類: 1. focus 2. blur 3. select 4. submit 5. change 瀏覽器前綴: ![image](https://hackmd.io/_uploads/rJNo_El5p.png) 連接網路API -> CDN,也可以下載到本地端做引用 npm是Node.js預設的、用JavaScript編寫的軟體套件管理系統。 ## 3. 第三周: ### **一(方法、語法).** ### **二(文字筆記).** ## 4. 第四周: ### **一(方法、語法).** ### **二(文字筆記).**