0%

ES6 章節

關於ES6新增的語法

  1. 讓原有的 JS 語法撰寫更為精簡 (語法糖)
  2. 讓 JS 撰寫觀念更為直覺、簡便 (新方法)

變數

  • var 宣告變數是定義了一個全域變數,或是在整個 function 而不管該區塊範圍。

    函式作用域(function scope)。

  • var 可以重複宣告,後宣告的值會取代前宣告的。
  • 有提升(Hoisting)的特性。
為了解決 var 可能造成程式碼的錯誤,ES6 中新增了2種變數宣告方式。

let

let: 可以宣告只能在目前區塊、階段或表達式中作用的變數。

  • 作用範圍是它們被定義的區塊,以及該區塊包含的子區塊。

    區塊作用域(block scope){}

  • 無法重複宣告
  • 有暫時性死區(TDZ) (TDZ 與 Hoisting 不同)
    1. 一樣會有創造階段。
    2. 但從創造階段到實際宣告會出現 TDZ ,這個區域無法呼叫變數。
    3. 有創造到執行的概念,但不會預先出現 undefined ,而是會出現錯誤提示。

const

const: Constants (常數) ,具有區塊可視範圍。常數不能重複指定值,也不能重複宣告。

  • 作用範圍是它們被定義的區塊,以及該區塊包含的子區塊。

    區塊作用域(block scope){}

  • 不可再指定(can’t re-assignment)。無法使用賦值運算子再次賦予值給此變數

    但如果宣告的常數是一個物件或陣列類型,像這種參照類型的值,裡面的值是可以作改變的。

  • 有暫時性死區(同 let )。

字串

舊有組字串的方式是使用引號 ' " & 運算子 + 來組合,可讀性不佳。

ES6 中新增了Template literals,可以輕鬆進行字串相加。

Template literals

  1. 將所有字串以反引號 ` 包覆。
  2. 變數則使用 ${} 來進行插入。
  3. 因換行符號是 Template literals 的一部份,以反引號 ` 包覆多行字串,可達到多行字串的效果。
  4. ${} 內也可以使用 javascript 方法。

MDN

函式

箭頭函式簡介

  • JS函式表達式
const callName = function(someOne) {
return '我是 ' + someOne;
}
console.log(callName(某某)) //我是 某某
  • 箭頭函式
    function 移除,並於 () 後方加入 =>
const callName = (someOne) => {
return '我是 ' + someOne;
}
console.log(callName(某某)) //我是 某某
  • 如果程式碼為表達式可以縮寫
    • 當箭頭函式裡的內容只有單行的時候,我們可以拿掉 return 和外面的大括號 {},會自動 return 。
      const callName = (someOne) => '我是 ' + someOne;
      console.log(callName(某某))
    • 如果輸入的參數只有一個,我們可以移除掉外面的括號
        const callName = someOne => '我是 ' + someOn;
      console.log(callName(某某)) //我是 某某
    • 沒有傳入參數的情況下, () 不可省略。
      const callName = () => '我是 ' + '某某'
      console.log(callName()) //我是 某某

與傳統函式不同之處

沒有 arguments 參數

  • 原始寫法
    const num = function() {
    console.log(arguments)
    }
    console.log(num(1,2,3,4,50,60,70,90,100))
    //Arguments(9) [1, 2, 3, 4, 50, 60, 70, 90, 100, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  • 箭頭函式,使用 arguments 會出現錯誤
    const num = () => {
    console.log(arguments)
    }
    console.log(num(1,2,3,4,50,60,70,90,100)) //arguments is not defined
  • 可以使用 其餘參數 解決此問題
    const num = (...arg) => {
    console.log(arg)
    }
    console.log(num(1,2,3,4,50,60,70,90,100)) //[1, 2, 3, 4, 50, 60, 70, 90, 100]

this 綁定的差異

  • 原始寫法
    var name = "全域"
    const local = {
    name: "區域",
    callName : function() {
    console.log('1.', this.name);
    setTimeout(function () {
    console.log('2.', this.name)
    console.log('3.', this)
    }, 10)
    }
    }
    local.callName()
    1. 區域
    2. 全域
    3. Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
      setTimeout 屬於 簡易呼叫,所以 this 指向全域 window
  • 箭頭函式,沒有自己的 this
    1. setTimeout 改成箭頭函式
      var name = "全域"
      const local = {
      name: "區域",
      callName : function() {
      console.log('1.', this.name);
      setTimeout(() => {
      console.log('2.', this.name)
      console.log('3.', this)
      }, 10)
      }
      }
      local.callName()
      1. 區域
      2. 區域
      3. {name: “區域”, callName: ƒ}
        因 箭頭函式,沒有自己的 this ,故指向上一層的物件(此時為 local 此物件)
    2. 物件內的 function 改成箭頭函式
      var name = "全域"
      const local = {
      name: "區域",
      callName : () => {
      console.log('1.', this.name);
      setTimeout(() => {
      console.log('2.', this.name)
      console.log('3.', this)
      }, 10)
      }
      }
      local.callName()
      1. 全域
      2. 全域
      3. Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
        因 箭頭函式,沒有自己的 this ,故指向上一層的物件(此時為 window 此物件)
    3. const vm = this
      var name = "全域"
      const local = {
      name: "區域",
      callName () {
      const vm = this
      console.log('1.', vm.name);
      setTimeout(() => {
      console.log('2.', vm.name)
      console.log('3.', vm)
      }, 10)
      }
      }
      local.callName()
      1. 區域
      2. 區域
      3. {name: “區域”, callName: ƒ}
        使用變數 vmthis 鎖定指向此物件,而後宣告此 vm 變數的接指向此物件。

DOM 指向的 this 也不同

因 箭頭函式,沒有自己的 this,所以 this 指向全域 window

無法透過 call、apply、bind 重新給予 this

因 箭頭函式,沒有自己的 this,所以 this 指向全域 window

var name= '全域'
const local = {
name: '區域'
}
//原始方式
const fn = function (para1, para2) {
console.log(this.name, para1, para2)
}
fn.call(local, 1, 2) //區域 1 2
//箭頭函式方式
const arrowFn = (para1, para2) => {
console.log(this.name, para1, para2)
}
arrowFn.call(local, 1, 2) //全域 1 2

無法作為建構式使用

const Fn = function (a) {
this.name = a
}
const arrowFn = (a) => {
this.name = a
}
console.log(Fn.prototype, arrowFn.prototype) //{constructor: ƒ} undefined
const a = new Fn('a')
console.log(a) //Fn {name: "a"}

const b = new arrowFn('b') //TypeError: arrowFn is not a constructor
console.log(b)

promise

promise

展開與其餘

陣列展開 (…Spread)

  • 陣列合併
    const array1 = ['HTML', 'CSS', 'JavaScript'];
    const array2 = ['pug', 'sass', 'Vuejs'];
    const allArray = [...array1, ...array2];
    console.log(allArray) // ["HTML", "CSS", "JavaScript", "pug", "sass", "Vuejs"]
  • return 概念
  • 淺複製 (shallow copy)
    // 陣列與物件為傳參考特性
    const array1 = ['HTML', 'CSS', 'JavaScript'];
    const array2 = array1
    array2.push('php');
    console.log(array1) // (4) ["HTML", "CSS", "JavaScript", "php"]
    // 淺拷貝
    const array1 = ['HTML', 'CSS', 'JavaScript'];
    const array2 = [...array1]
    array2.push('php');
    console.log(array1) // (3) ["HTML", "CSS", "JavaScript"]
  • 類陣列轉換成純陣列
    • 類陣列有如以下
    • arguments(function 傳入多餘的參數)
    • NodeList (document.querySelectorAll 的 DOM元素)
    const f = function() {
    console.log(arguments); // Arguments [1, 2, 3, 4, 5, 6]
    const arg = [...arguments];
    console.log(arg) // [1, 2, 3, 4, 5, 6]
    arg.forEach((i)=> {
    console.log(i)
    })
    }
    f(1, 2, 3, 4, 5, 6);

參數其餘 (…Rest)

  • 使用其餘參數取代 arguments
  • 其餘參數產生的是純陣列
    const f = function(a, ...b) {
    console.log(a, b)
    }
    f(1, 2, 3, 4, 5, 6);
    // 1
    // [2, 3, 4, 5, 6]

解構賦值(Destructuring)

解構賦值可以想像是鏡子的概念,將右方的資料往左邊送,然後會一個位置對一個值 (但沒有像鏡子左右顛倒)。

解構賦值仍然是一種指定運算的語句。指定運算在等號(=)的左邊是要被指定的變數/常數識別名稱,右邊的則是要指定的值。

陣列

使用於陣列中特別的兩點

  1. 可以用其餘運算符(Rest Operator)的語法,會把其餘的對應值集合成一個陣列之中。
  2. 可以交換(Swap)陣列中的值的語法。
  • 基本用法
    const [a, b] = [1, 2] //a=1, b=2
  • 先宣告後指定值,需使用 let
    let a, b
    [a, b] = [1, 2]
  • 略過某些值
    const [a, , b] = [1, 2, 3] // a=1, b=3
  • 其餘運算符(...)
    const [a, ...b] = [1, 2, 3] //a=1, b=[2,3]
  • 失敗保護
    const [, , , a, b] = [1, 2, 3] // a=undefined, b=undefined
  • 交換值
    const a = 1, b = 2;
    [b, a] = [a, b] //a=2, b=1
  • 多維複雜陣列
    const [a, [b, [c, d]]] = [1, [2, [[[3, 4], 5], 6]]]
  • 字串
    const str = "基紐特戰隊";
    const [a, b, c, d, e] = str // "基", "紐", "特", "戰", "隊"

物件

物件則是使用物件的屬性名稱來做對應(因此沒有順序性)。

  • 基本用法
    const { user: x } = { user: 5 } // x=5
  • 失敗保護(Fail-safe)
    const { user: x } = { user2: 5 } // x=undefined
  • 賦予新的變數名稱
    const { prop: x, prop2: y } = { prop: 5, prop2: 10 } // x=5, y=10
  • 預設值
    const { prop: a = 5 } = {} //  a = 5
  • 屬性賦值語法
    const { prop: prop, prop2: prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
  • 相當於上一項的簡短語法(Short-hand syntax)
    const { prop, prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
  • ES7+的物件屬性其餘運算符
    const {a, b, ...rest} = {a:1, b:2, c:3, d:4} //a=1, b=2, rest={c:3, d:4}

類別 (class)

class 是 ES6 推出的語法糖(JS 本質仍是原型繼承(prototype-based))

  • 定義
    class className {
    constructor (para1, para2, ...) {
    this.para1 = para1;
    this.para2 = para2;
    }
    method1() {
    // function 內容
    }
    // method2, method3, ...
    }
    let A = new className(para1, para2, ...)
  • 使用
    class BMI_calc {
    constructor (height, weight) {
    this.weight = weight;
    this.height = height;
    }
    calc() {
    return Math.round(this.weight / (Math.pow((this.height / 100), 2)))
    }
    }
    let BMI = new BMI_calc(172, 70);
    console.log(BMI.calc()); // 24

縮寫 (shorthand)

  • 物件縮寫
    將兩個物件合併至一個物件上。
    • 原方式
      const Frieza = '弗利沙'
      const GinyuTeam = {
      Ginyu: '基紐',
      Jeice: '吉斯',
      burter: '巴特',
      }
      const newTeam = {
      Frieza: Frieza,
      GinyuTeam, GinyuTeam
      }
      console.log(newTeam) // {Frieza: "弗利沙", GinyuTeam: {…}}
    • 縮寫
      const Frieza = '弗利沙'
      const GinyuTeam = {
      Ginyu: '基紐',
      Jeice: '吉斯',
      burter: '巴特',
      }
      // 物件內的屬性名稱與來源變數一致時,可不需重複寫
      const newTeam = {
      Frieza,
      GinyuTeam
      }
      console.log(newTeam) // {Frieza: "弗利沙", GinyuTeam: {…}}
  • 物件內函式縮寫
    • 原方式
      const newObject = {
      foo: function() {
      // do soming
      }
      }
    • 縮寫
      // 將 function 移除
      const newObject = {
      foo () {
      // do soming
      }
      }
      // 但使用箭頭函式結果會不一致
  • 搭配解構使用
    將以下物件指向賦予到另一個物件上,並且避免參考
    const GinyuTeam = {
    Ginyu: {
    name: '基紐'
    },
    Jeice: {
    name: '吉斯'
    },
    Baata: {
    name: '巴特'
    }
    }
    const newTeam = { ...GinyuTeam };
    // 可保持原物件的架構,並且不會因為傳參考特性影響

for…of

  1. 推薦在迭代物件屬性時,使用 for...in;在迭代陣列時,使用 for...of
  2. for...in 輸出的是屬性名稱(key)for...of 輸出的是值(value)
  3. for...of 是 ES6 的新語法。修復了ES5 for...in 的不足
  4. for...of 不能迭代物件,需要透過和 Object.keys() 搭配使用。
for...in for...of
for(let index in aArray){
console.log(`${aArray[index]}`);
}
for(var value of aArray){
console.log(value);
}
  1. for...infor...of的差別
    // 在物件和陣列的原型鍊上,分別各新增function
    Object.prototype.objCustom = function () {};
    Array.prototype.arrCustom = function () {};

    let iterable = [3, 5, 7];
    // 在陣列,新增一個屬性 foo
    iterable.foo = "hello";

    for (let i in iterable) {
    console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
    }

    for (let i of iterable) {
    console.log(i); // 3, 5, 7
    }
  2. for..of 迭代 物件(object)
    var student={
    name:'wujunchuan',
    age:22,
    locate:{
    country:'taiwan',
    city:'taipei',
    school:'UCCU'
    }
    }
    for(var key of Object.keys(student)){
    //使用Object.keys()方法獲取物件key的陣列
    console.log(key+": "+student[key]);
    }

import & export

ES6的模組系統使用上相當簡單

  • ES6的模組程式碼會自動變成 strict-mode (嚴格模式),不論你有沒有使用 "use strict" 在程式碼中。
  • ES6的模組是一個檔案一個模組
  • ES6模組使用 export (輸出)與 import (輸入)語句來進行模組輸出與輸入。輸出通常位於檔案最後,輸入位於最前面。
  • export 分別有 exportexport default ,兩者最大的差異是 export 可以有多個,但 export default 只能存在一個。

export

export const arr = [1, 2, 3, 4];
export const aString = 'this is a string'
export function aFunction(){
console.log('function test')
};
export class aClass {
constructor(name, age){
this.name = name
this.age = age
}
}

有兩種方式可以將以輸出的模組進行輸入。

  1. 解購賦值方式,可另外 alias 一個模組名稱
    import { arr, aFunction, aClass } from "./module.js";
    import { aString as myString } from "./module.js";

    console.log(arr);
    console.log(myString);
    aFunction()
  2. 使用萬用字元 * 但需要 alias 一個模組名稱
    import  * as myModule from './module.js'

    console.log(myModule.arr);
    console.log(myModule.aFunction())

    const newObj = new myModule.aClass('Inori', 16);
    console.log(newObj)

export default

對單一輸出的模組就不需要使用解構賦值,這代表只輸入以 default 值定義的輸出模組。

function aFunction(param){
return param * param
}
export default aFunction;
import aFunction from './module.js'