[ 筆記 ] JavaScript - ES6語法


Posted by krebikshaw on 2020-06-29

ES6 概念

ECMAScript 是 JavaScript 的一種語言標準。ES6 代表著 ECMAScript6 這個版本。

支援的瀏覽器

ECMAScript 6 ( ES6 ) 於 2015 年發布,支援的瀏覽器可參考 ECMAscript ES6 支援表

參考資料:[ES6] Javascript 開發者必須知道的 10 個新功能

ES6 新語法

let & const:新的變數宣告方法

  • let 及 const 都是區塊作用域 block scope
  • 相較於 ES5 的變數宣告只有 var,let 跟 const 的作用域有所不同。

const 當變數是個常數(不會改變),它不會被重新賦值,就可以使用 const 來宣告

  • 對於 原始型態 的變數,基本上就是宣告後就不能再改變數值
  • 對於 物件型態 的變數,不能變的是 記憶體位置 ,裡面的內容還是可以變的
    • 所以可以改物件裡面的內容,但不能重新賦值一個新的物件
      const pi = 3.14
      const button = document.querySelector('btn')
      

let

  • 未宣告之前不可以使用:相較於 var 會有變數提升 ( Hoisting ) 的特性( 變數可以在宣告前使用,值為 undefined ), let 在宣告之前不能使用。

    console.log(name); // undefined
    var name = 'Anbulent'; 
    console.log(dog); // 錯誤:dog is not defined
    let dog = 'Lucky';
    
  • 塊級作用域: var 的變數會存活在整個 function 的範圍之中,而 let 跟 const 作用域是在大括號 { } 裡面(也就是說在 if 裡面宣告的變數,在 if 之外就抓不到了),可以避免污染到其他的變數

    if (true) {
      var dog = 'Lucky';
      let name = 'Anbulent';
      const PI = 3.14;
    }
    console.log(dog); // Lucky
    console.log(name); // 錯誤: name is not defined
    console.log(PI); // 錯誤: PI is not defined
    

Template Literals 模板字串符

  • 可用於字串拼接
  • 或隔行字串(以往多行字串結尾都要加上 \n 換行,再加上一堆引號跟加號,非常難閱讀)
// 字串拼接,將變數 放入 ${ } 之中
console.log(`${name}'s dog is ${dog}.`);

// ES5
var str = '開頭\n' + 
'多行字串\n' +
'結束';
console.log(str);

// ES6
var str2 = `開頭
多行字串
結束`;
console.log(str2);
  • 可以在模板字串符中使用函式
  • 甚至可以在模板字串符的函式中寫判斷式
// 用 ${} 來使用函式
let newUl = `
  <ul>
    ${people.map(person => `<li>我叫做 ${person}</li>`).join('')}
  </ul>
`
// 在函式中加入判斷式
const people = [
  {
    name: '老大',
    friends: 2
  },
  {
    name: '老二',
    friends: 16
  },
  {
    name: '老么',
    friends: 0
  }
]

let newUl = `
  <ul>
    ${people.map((person) => {
        if (person.friends) {
          return `<li>${person.name} 有 ${person.friends} 朋友</li>`
        } else {
          return `<li>${person.name} 沒朋友</li>`
        }
      }).join('')
    }
  </ul>
`

console.log(newUl);
//  <ul>
//    <li>老大 有 2 朋友</li><li>老二 有 999 朋友</li><li>老么 邊緣人</li>
//  </ul>

Destructuring 解構

通過匹配 array 中的第 n 值,或是 object 內對應的 key 的值,賦值到變數,可以同時做到「變數宣告」和「變數賦值」兩件事情。

// 陣列 ------
let arr = [1, 2, 3, 4, 5];
let [first, second] = arr; // 變數對應到 arr 的 序
console.log(first); // 1
console.log(second); // 2

// 物件 ------
let obj = { 
    name: 'Alex',
    dog: 'Lucky',
    family: {
        father: 'Peter'
    }
}
let {name, dog} = obj; // 變數要對應到 obj 的 key
let {family: {father}} = obj; // 也可以對應到更裡面,但只會取出最深處的變數,此例是 father
console.log(name); // Alex
console.log(dog); // Lucky
console.log(father); // Peter
console.log(family); // 錯誤:family is not defined

/* 舊的 ES5 寫法 ---
var first = arr[0];
var second = arr[1];

var name = obj.name;
var dog = obj.dog;
var father = obj.family.father;
-------------------
*/
  • 陣列是使用順序的索引值對應,但物件則是使用物件的屬性名稱來做對應(因此沒有順序性)。

  • 解構的好處 是提取 JSON 的時候很方便

let ajax_JSON = {
  id: 9527,
  name: 'Kanboo',
  other: {
    tel: '1234567',
    fax: '7654321'
  }
};

let {
  id,
  name,
  other: { tel }
} = ajax_JSON;

console.log(id, name, tel); // 9527 "Kanboo" "1234567"

Spread Operator 展開運算子

展開運算子是 ”把一個陣列展開(expand)成個別數值“ 的速寫語法,簡單來說,就是 把陣列裡面的值,拆解成一個一個。

let arr2 = ['a', 'b'];
let arr3 = ['c', 'd'];
console.log([...arr2, ...arr3]); // [ 'a', 'b', 'c', 'd', 'e' ]
console.log(['new', ...arr2, 'last']); // [ 'new', 'a', 'b', 'last' ]

arr2.push(...arr3);
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

let name = [...'Alex'];
console.log(name); // [ 'A', 'l', 'e', 'x' ]

let obj = {name : 'Alex'}
let obj2 = {...obj};
console.log(obj2); // { name: 'Alex' }
console.log(obj === obj2); // false,記憶體位置不同

Rest Parameters 其餘運算子

// 可傳入不固定的參數,1個 or 多個 皆可…
function sum(...numbers) {
  var result = 0;
  numbers.forEach(function (number) {
    result += number;
  });
  return result;
}

//傳入一個值
console.log(sum(1)); // 1
//傳入多個值
console.log(sum(1, 2, 3, 4, 5)); // 15

let arr = [1, 2, 3, 4, 5];
let [first, second, ...rest] = arr;
console.log(...rest); // 3, 4, 5

let obj = {
    a: 1,
    b: 2,
    c: 3
}
let {a, ...obj2} = obj; // ...集合
console.log(a, obj2); // 1 { b: 2, c : 3 }

let obj3 = {
    ...obj2, // ...展開
    d: 4
}
console.log(obj3); // { b: 2, c: 3, d: 4 }
  • 其餘參數(Rest parameters)有一個限制,就是這個參數一定是函式的「最後一個」。(如果放在其餘的參數前,就會產生錯誤)

Default Parameters 參數預設值

// 可以幫函式的參數加上預設值
function whosDog(name = 'Alex', dog = 'Lucky'){
    return `${name}'s dog is ${dog}`;
}
console.log(whosDog()); // Alex's dog is Lucky
console.log(whosDog('小明', '小花')); // 小明's dog is 小花

// 也可以搭配解構使用,幫不存在的 c 丟入預設值
let obj = {
    a: 1, 
    b: 2
}
let {a = 'a', b = 'b', c = 'c'} = obj;
console.log(a, b, c); // 1 2 'c'

Arrow Function 箭頭函式

一般使用箭頭函式與 function 的用法大致一致,可以傳入參數、也有大括號包起來

  • 只有一個回傳值,可以省略 return ( 但是如果有寫大括號 {} 就得加上 return,如果沒有傳入值則會出現 undefined)
  • 只有一個參數,可以省略括號 ( )
// 正常寫法
var callSomeone = (someone) => {
  return someone + '上工了'
}
console.log(callSomeone('伙計'))

// 縮寫,單一行陳述不需要 {}
var callSomeone = (someone) => someone + '上工了'
console.log(callSomeone('伙計'))

// 只有一個參數可以不加括號
var callSomeone = someone => someone + '上工了'
console.log(callSomeone('伙計'))

// 沒有參數時,一定要有括號
var callSomeone = () => '伙計' + '上工了'
console.log(callSomeone('伙計'))

// 有寫大括號 {} 就一定要加上 return
var callSomeone = (someone) => { someone + '上工了' }
console.log(callSomeone('伙計')) // undefined
  • 實用的操作方式

    let arr = [1, 2, 3, 4, 5]
      .filter(value => value > 1)
      .map(value => value * 2);
    console.log(arr); // [ 4, 6, 8, 10 ]
    
  • 補充:箭頭函式裡面的this 等於 外面的this
    箭頭函式裡的this 主要是依據 外層函式(function)裡的this 是什麼就跟著是什麼。

ES6模組的輸出與輸入

使用 export 加在在想要輸出部分的前面,物件、類別、函式與原始資料(變數與常數)都可以輸出

// 分開來一個一個輸出
export const aString = 'test'

export function aFunction(){
  console.log('function test')
}

export const aObject = {a: 1}

export class aClass {
  constructor(name, age){
    this.name = name
    this.age = age
  }
}

// 用 { } 包起來一起輸出
const add = (a, b) => a + b;
const PI = 3.14;

export {
    add,
    PI
}

有兩種方式可以進行輸入,一種是每個要輸入的名稱都需要定在在花括號({})之中,另一種是用 *,但要自行定義一個模組名稱(避免命名衝突)

// 使用 {} 將要引入的東西寫在裡面
import {aString, aObject, aFunction, aClass} from './lib.js'

console.log(aString)
console.log(aObject)

// 使用 * 全部引入,自行定義一個模組名稱叫做 myModule
import  * as myModule from './lib.js'

console.log(myModule.aString)
console.log(myModule.aObject)

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

Babel

Babel 是一個 JavaScript 的轉譯器,可以幫你轉成需要的版本、輕鬆解決以上問題,意思是你依舊可以使用潮潮的最新語法,而不用為了使用者環境而吐血。

  • 設定步驟:
    1. 安裝必要套件:npm install --save-dev @babel/core @babel/node @babel/preset-env
    2. 新增 Babal 的設置檔:.babelrc
    3. .babelrc 裡輸入以下內容,告訴 babel 要用這個 preset:
      {
      "presets": ["@babel/preset-env"]
      }
      
    4. 最後使用 npx babel-node <index.js> 運行即可

參考資料:
[筆記] JavaScript ES6 中的模版字符串(template literals)和標籤模版(tagged template)
Webpack教學 (四):JavaScript 與 Babel


#ES6







Related Posts

[Bug Record] — binary classification accuracy converges to 0.5

[Bug Record] — binary classification accuracy converges to 0.5

v-if / v-else 使用細節

v-if / v-else 使用細節

React(8) - CSS in JS

React(8) - CSS in JS


Comments