---
# System prepended metadata

title: JavaScript筆記
tags: [前端, js]

---

# JavaScript ES6
早期JavaScript只能用**var**宣告變數
ES6後，多了兩種方式：
- let
- const

## let 宣告變數 
```
// 宣告變數x
let x;

//宣告變數y的同時，指定資料
let y = 3;
```

## const宣告常數
宣告常數
> 常數：一旦設定好資料，在程式中就無法再修改
```
// 宣告常數PI(一定要指定資料，他不會變動)
cons PI = 3.14159;
```
# let, const, var?
這些的差距是什麼？
## var
使用var宣告變數，他的Scope(可用範圍)以==函式區塊==分界
舉個栗子
> 片段01
> 下方程式碼沒有任何函式，所以整塊程式屬於同一Scope
> [color=#FF9797]
```javascript!
for(var i=0; i<3; i++){
    console.log(i);
}
console.log(i); //print 3
// 雖然i被宣告在for迴圈裡面，可以迴圈外仍然可以接收到i的內容
```

---

> 片段02
> 下方程式碼有一個函式，內部是一個Scope，外部是另一個Scope
> 所以函式外部的`console.log(i)`會找不到內部Scope的**宣告變數i**
> [color=#FF9797]
```javascript!
function test(){
    for(var i=0; i<3; i++){
        console.log(i);
    }
}
console.log(i); //錯誤，會找不到變數
```
## let
ES6最新的設定let
使用let宣告變數，變數的Scope以 ==程式區塊(大括號)== 為分界
> 片段01
> 相比上面var宣告，本次使用**let**為i宣告
> 所以在for迴圈裡面已經是一個Scope了，for迴圈外面是另一個Scope
> 外面的console.log(i)沒辦法讀去到 let i
> [color=#FF9797]
```javascript!
for(let i=-; i<3; i++){
    console.log(i);
}
console.log(i); //error， not find `i`
```

---

> 片段02
> 不僅僅只有let宣告，還多一層函式
> 同樣，不同Scope，讀取不到裡面內容
> 外面的console.log(i)還是沒辦法讀去到 let i
> [color=#FF9797]
```javascript!
function test(){
    for(let i=-; i<3; i++){
        console.log(i);
    }
}
console.log(i); //error， not find `i`
```
## const
ES6中最新的const
使用const宣告常數，常數的資料==不能變動==，任何都不行
在進行宣告時，一定！要給<big><big>**資料**</big></big>！
舉個栗子：
```javascript!
// ex.01
var v=3;
v = "Hello World"; //var宣告的變數，可變動

//ex.02
let l;
l = 0; //變數中的資料可變動

//ex.03
const x;  //error: 常數宣告時一定要給**資料**！

//ex.04
const c=100;
c = 50; //error: 不能更動常數中的資料！
```
# 箭頭函式(Arrow Function)
JacaScript傳統上使用==function==建立函式
從ES6開始， <big><big>==`=>`==</big></big> 其效用等於**funciton**
語法：
## (參數列表)=>(回傳值)
栗子：
```javascript!
// 傳統函式寫法
let add=function(n1, n2){
    return n1+n2;
}

// Arrow Function
let add=(n1, n2)=>(n1+n2);
```
## (參數列表)=>{函式內部程式}
栗子：
```javascript!
// traditional
let add=function(n1, n2){
    return n1+n2;
}

// Arrow Function
let add=(n1, n2)=>{
    return n1+n2;
}
```
## 匿名函式(沒有名字)
```javascript!
//在排程中使用"傳統函式" 撰寫"匿名函式"
setTimeout(function(){
    console.log("過了一秒鐘");
}, 1000);   //1000是毫秒，在一秒鐘之後執行上面函式

//在排程中使用"箭頭函式" 撰寫"匿名函式"
setTimeout(()=>{
    console.log("過了一秒鐘");
}, 1000);
```
# 函式參數的預設值(Default Prarmeter)
如何指定函式參數的==預設值==？
## 傳統寫法
```javascript!
// traditional
function show(msg){
    if(typeof msg==="undefined"){ //未給定msg的資料
        msg="預設值";
    }
    alert(msg);
}

show("Hello");  //print "Hello"

show();  //print "預設值"
```
## ES6寫法
==(name=預設值, name=預設值)==
```javascript!
// 若未給定msg資料，直接採用 = 後方指定資料
function show(msg="預設值"){
    alert(msg);
}

show("Hello");  //print "Hello"

show(); //print "預設值"
```

---
用 **"箭頭函式"**

```javascript!
//Arrow Function
let show=(msg="Default")=>{
    alert(msg);
}

show("Hello");

show();
```
## 其他範例
![image](https://hackmd.io/_uploads/SJoiwyL3T.png)

---
![image](https://hackmd.io/_uploads/HJJydyIna.png)

# 類別與物件的基本觀念
定義：
**類別** 比喻為 設計圖
**物件** 比喻為 根據設計圖製造出來的實體
:::info
:exclamation: 一個==類別==設計
可以用來產生無數的==物件實體==
:::
![image](https://hackmd.io/_uploads/BJY6K1U2T.png)

## 基本類別設計會用到的關鍵字
- class
- constructor
## 產生物件實體會用到的關鍵字
- new
# 定義類別並產生物件
如何定義類別，並且如何根據定義好的類別產生物件實體
- class 類別名稱{}  --> 定義類別
- new 類別名稱()  --> 建立物件

```javascript!
// define class
class Car{}

// use class, new a object
// put new Car() in variable 'car1'
let car1 = new Car();

// new the second object
let var2 = new Car();
```
示意圖：
![image](https://hackmd.io/_uploads/rkGw21L26.png)
# 定義建構式(Constructor)
在類別中定義建構式。
```javascript!
/*建構式一定定義在類別之中*/
constructor(參數列表){
    建構式的內部程式
}
```
:::warning
**constructor** 一定要寫！
:::
![image](https://hackmd.io/_uploads/BJjlLz4ap.png)
```javascript!
// define class
class Car{
    // 類別中定義建構式
    constructor(){
        console.log("建構式被呼叫");
    }
}

// use class, new a object
// put new Car() in variable 'car1'
let car1 = new Car(); //呼叫建構式，產生新物件

// new the second object
let var2 = new Car(); //呼叫建構式，產生新物件
```
### 建構式：==當在建立新物件時==　被呼叫的函示
不過沒有特別寫的話，會自己內建一個空白的建構式。
`constructor(){}`
# 定義、存取屬性(Attribute)
在類別中定義、存取裡面的屬性
## 物件屬性(Attribute)
用來描述物件的個別差異
通常在建構式中建立屬性。
```javascript!
// 建構式
constructoe(參數列表){
    // this: 正要產生的新物件
    this.屬性名稱 = 初始資料;
}
```
範例
```javascript!
// define class
class Car{
    constructor(){
        this.color="red"; // 建立新屬性color，指定資料"red"
    }
}

// use class, new a object
let car1 = new Car(); //新物件擁有color屬性，資料為red
let var2 = new Car(); //新物件擁有color屬性，資料為red
```
:::warning
上面的屬性都是一樣的，我們希望在new新的物件時，color的值是由物件本身賦予。
:::
```javascript!
// define class
class Car{
    constructor(color){
        // 建立新屬性color，資料透做參數，彈性的、在建立物件時提供
        this.color="red"; 
        // 建構式也是一個函式的概念，所以也可以在裡面放參數
    }
}

// use class, new a object
let car1 = new Car("blue"); //新物件擁有color屬性，資料為blue
let var2 = new Car("green"); //新物件擁有color屬性，資料為green
```
## 存取物件屬性
:::info
物件.屬性名稱

物件.屬性名稱=新的資料
:::
```javascript!
// define class
class Car{
    constructor(color){
        this.color=color;
    }
}

// new object
let car1 = new Car("blue"); // 新物件的color屬性資料為 "blue"
console.log(car1.color); // 取的資料的color屬性，印出 "blue"

car1.color="red"; //更新color屬性資料
console.log(car1.color); // 取的new資料的color屬性，印出 "red"
```
# 定義、呼叫方法(Method)
在類別中定義，並且呼叫方法
![image](https://hackmd.io/_uploads/B1iUN8Ea6.png)
:::warning
**方法(Method)** ：用來描述物件可以做的事情、與物件綁定的函式
:::
### 如何建立方法??
:::info
在類別中建立方法

方法的名稱(參數列表){
    內部的程式碼
}
:::
舉個栗子
```javascript!
// define
class Car{
    constructor(color){
        this.color=color;
    }
    
    // define 'run' method
    run(){
        consloe.log("Running");
    }
}

// new object
let car1 = new Car("blue");
// 此物件擁有color屬性，和run方法
```
### 如何呼叫物件方法
:::info
物件.方法名稱(參數資料)
:::
```javascript!
// define
class Car{
    constructor(color){
        this.color=color;
    }
    
    // define 'run' method
    run(){
        consloe.log("Running");
    }
}

// new object
let car1 = new Car("blue");
// 此物件擁有color屬性，和run方法

car1.run(); // 呼叫run方法，執行內部程式後印出Running
```
### this 綁定物件
在**物件方法**中使用**this**代表==綁定的物件==
```javascript!
// define
class Car{
    constructor(color){
        this.color=color;
    }
    run(){
        // this.color 代表新物件建立時，上面的color屬性
        consloe.log("Car " + this.color +" Running");
    }
}

// new object
let car1 = new Car("blue");
car1.run(); // 最後會印出Car blue Running
```
### 物件、方法的綜合
```javascript!
class Car{
    constructor(color){
        this.color=color;
        this.speed=0;
    }
    run(speed){
        this.speed=0; //update car speed
        console.log("Car "+ this.color + " Running at " + this.speed+ "KM/HR");
    }
    stop(){
        this.speed=0; // updatte car speed
        console.log("Car "+ this.color+" Stopped");
    }
}

let car1 = new Car("blue");
car1.run(50);  // speed = 50
car1.stop();   // speed = 0
```
# 類別繼承基本觀念
![image](https://hackmd.io/_uploads/Hy3afwN6T.png)
根據父層的主要骨幹，在子類別再新增其他的項目。
:::success
會用到的關鍵字：==extends, super==
:::
## 定義子類別
![image](https://hackmd.io/_uploads/SJoI7PNpp.png)

#### 定義子類別
> class 子類別名稱 extends 父類別名稱{}
#### 建立子類別物件
> new 子類別名稱()
#### 定義子類別建構式
> constructor(){
> // 一定要先呼叫父類別建構式
> super();
> //子類別建構式中的其他程式
> }

```javascript!
// 父類別
class Car{
    constructor(){
        console.log("父類別建構式");
    }
}
// 子類別
class ElectricCar extends Car{
    constructor(){
        super(); // 一定要先呼叫父類別建構式！
        console.log("執行子類別建構式，衍伸出ElectricCar 物件");
    }
}

// 產生子類別物件
let car = new ElectricCar();
```
## 加入屬性
```javascript!
// 父類別
class Car{
    constructor(color){
        this.color=color; // define color
    }
}
// 子類別
class ElectricCar extends Car{
    constructor(color){
        super(color); // 繼承父類別的color
        console.log("執行子類別建構式，衍伸出ElectricCar 物件");
    }
}

// 產生子類別物件
let car = new ElectricCar("green");
console.log("car's color: "+ car.color); // print green
```
## 加入方法
```javascript!
// 父類別
class Car{
    constructor(color){
        this.color=color; // define color
    }
    run(){
        console.log("Car "+this.color+" is Running");
    }
}
// 子類別
class ElectricCar extends Car{
    constructor(color){
        super(color); // 繼承父類別的color
        console.log("執行子類別建構式，衍伸出ElectricCar 物件");
    }
}

// 產生子類別物件
let car = new ElectricCar("green");
car.run();  // 子類別同樣擁有付類別中定義的「方法」
```
## 在子類別中加入屬性
```javascript!
// 父類別
class Car{
    constructor(color){
        this.color=color; // define color
    }
    run(){
        console.log("Car "+this.color+" is Running");
    }
}
// 子類別
class ElectricCar extends Car{
    constructor(color){
        super(color); // 繼承父類別的color
        this.battery=100; //衍生更多子類別，電動車專屬的定義
    }
}

// 產生子類別物件
let car = new ElectricCar("green");
car.run();  // 子類別同樣擁有付類別中定義的「方法」
```
## 子類別覆蓋父類別的方法
```javascript!
class Car{
    constructor(color){
        this.color=color; // define color
    }
    run(){
        console.log("Car "+this.color+" is Running");
    }
}
// 子類別
class ElectricCar extends Car{
    constructor(color){
        super(color); // 繼承父類別的color
        this.battery=100; //衍生更多子類別，電動車專屬的定義
    }
    /*定義run方法，覆蓋付類別的同名方法*/
    run(distance){
        this.battery=distance;
        console.log("這是子類別的方法");
    }
}
//下略
```
## 專屬子類別的方法
```javascript!
// 子類別
class ElectricCar extends Car{
    constructor(color){
        super(color); // 繼承父類別的color
        this.battery=100; //衍生更多子類別，電動車專屬的定義
    }
    /*定義run方法，覆蓋付類別的同名方法*/
    run(distance){
        this.battery=distance;
        console.log("這是子類別的方法");
    }
    /*專屬於子類別的方法*/
    charge(){
        this.battery=100;
    }
}

// new car object
let car = new ElectricCar("green");
car.run(10); // 使用子類別中重新定義的方法
car.charge() // 使用子類別中定義的方法
car.battert; // 子類別中定義的屬性
```
# 原型鍊(Prototype Chain)
原型物件：每個物件都有對應的原型物件
用javascript內建的工具==取得原型物件==
:::info
#### **Object.getPrototypeOf(物件)**
* 做好的物件，丟給他的參數，這個工具就會幫忙取得物件的**原型物件**
:::
![image](https://hackmd.io/_uploads/Bkc-oA8Ta.png)
下面舉個栗子，可在codepen看看他的運行後console
```javascript!
class Car{
    constructor(color){
        this.color=color;
    }
    run(){}
}

//new object
let car = new Car("blue");
let carProto = Object.getPrototypeOf(car); //Car class的原型物件
console.log(carProto);

//
let objProto = Object.getPrototypeOf(carProto); //Object的原型物件
console.log(objProto);

//
let lastOne = Object.getPrototypeOf(objProto); //原型鍊的終點
console.log(lastOne);
```
# 定義、呼叫靜態方法(Static Method)
靜態方法：與類別綁定的方法
:::info
static 方法的名稱(參數列表){
    內部的程式碼
}
:::
呼叫方法：
**類別名稱.方法名稱(參數資料)**
:::danger
:warning: 只有靜態方法才可以用 **類別名稱.方法名稱()**
若是一般方法的話，必須要 **物件實體.方法名稱()**
:::
# 非同步程式
非同步：程式中【包含子程式】時產生
ex.時間排成
