# 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.時間排成