# 前端學習筆記
## 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)結構**

**HTML 文件物件模型(DOM)結構** (每一個元素都是一個物件)

**應用程式編程介面(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 樹狀結構圖:

**以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
瀏覽器前綴:

連接網路API -> CDN,也可以下載到本地端做引用
npm是Node.js預設的、用JavaScript編寫的軟體套件管理系統。
## 3. 第三周:
### **一(方法、語法).**
### **二(文字筆記).**
## 4. 第四周:
### **一(方法、語法).**
### **二(文字筆記).**