# 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();
```
## 其他範例

---

# 類別與物件的基本觀念
定義:
**類別** 比喻為 設計圖
**物件** 比喻為 根據設計圖製造出來的實體
:::info
:exclamation: 一個==類別==設計
可以用來產生無數的==物件實體==
:::

## 基本類別設計會用到的關鍵字
- 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();
```
示意圖:

# 定義建構式(Constructor)
在類別中定義建構式。
```javascript!
/*建構式一定定義在類別之中*/
constructor(參數列表){
建構式的內部程式
}
```
:::warning
**constructor** 一定要寫!
:::

```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)
在類別中定義,並且呼叫方法

:::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
```
# 類別繼承基本觀念

根據父層的主要骨幹,在子類別再新增其他的項目。
:::success
會用到的關鍵字:==extends, super==
:::
## 定義子類別

#### 定義子類別
> 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(物件)**
* 做好的物件,丟給他的參數,這個工具就會幫忙取得物件的**原型物件**
:::

下面舉個栗子,可在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.時間排成