在 ES6 版本之後,Javascript 多了很多好用的語法,建議新手一定要學起來這幾招。

  • 原文出處:https://dev.to/azure/modern-javascript-10-things-you-should-be-using-starting-today-1adm

-1- 展開運算子 Spred operator

在物件或陣列前面寫 ... 可以很輕鬆地把資料展開,舉例來說:

Spread array

let firstHalf = [ 'one', 'two'];
let secondHalf = ['three', 'four', ...firstHalf];

寫起來非常簡潔。不然原本要這樣寫:

NO Array spread

let firstHalf = [ 'one', 'two'];
let secondHalf = ['three', 'four'];
for(var i=0, i <firstHalf.length; i++ ) {
  secondHalf.push(firstHalf[i]);
}

用在物件也可以,能夠合併屬性:

Spread object

const hero = {
  name: 'Xena - Warrior Princess',
  realName: 'Lucy Lawless'
}

const heroWithSword = {
 ...hero,
 weapon: 'sword'
}

不然的話,就要用迴圈來跑全部屬性:

NO Object spread

let keys = Object.keys(hero);
let obj = {};

for(var i=0; i< keys.length; i++) {
   obj[keys[i]] = keys[props[i]];
}

舊寫法其實有 Object.assign() 可以用,看起來會像:

const heroWithSword = Object.assign({}, hero, {weapon:"sword"})

但展開運算子還是簡潔多了:

const heroWithSword = {
 ...hero,
 weapon: 'sword'
}

-2- 其餘參數 Rest parameter

其餘參數能夠將剩下的參數蒐集到一個陣列中。JavaScript 有足夠彈性可以處理這些參數。通常會這樣寫:

function add(first, second, ...remaining) {
  return first + second;
}

以上只是加總前兩個參數,也就是 add(1,2) 或 add(1,2,3, 4) 結果一樣。接著這樣改寫:

function add(first, second, ...remaining) {
  return first + second + remaining.reduce((acc, curr) => acc + curr, 0);
}

這樣就會把全部參數都加總在一起了。

如您所見,前面加上 ... 就可以搜集其餘參數。這是一種命名變數的方式而已,比較少人知道這招,但可以知道一下。

-3- 字串插值 String interpolation

看過這種寫法嗎?

class Product {
  constructor(name, description, price) {
    this.name = name;
    this.description = description;
    this.price = price;
  }

  getDescription() {
    return " Full description \n" +
    " name: " + this.name +
    " description: " + this.description
  }
}

看看那個 getDescription() 方法,又長、跨行、又難讀。在大多數程式語言都只能這樣寫。幸好,有些程式語言支援字串插值,包括 JavaScript,所以可以改寫如下:

getDescription() {
  return `Full description \n:
  name: ${this.name}
  description ${this.description}
  `;

}

反引號 ` 可以定義多行字串。再使用 ${} 進行插值。是不是好多了呢:)

-4- 屬性縮寫 Shorthand properties

雖然還沒搞懂,你可能早就在用了。在 ES5 需要這樣寫:

function createCoord(x, y) {
  return {
    x: x,
    y: y
  }
}

在 ES6 之後,如果 : 後面名稱一樣,可以直接省略,像這樣:

function createCoord(x, y) {
  return {
    x,
    y
  }
}

簡潔多了吧?

-5- 方法屬性 Method properties

在物件裡面指向方法的寫法。以下是 ES5 寫法:

const math = {
  add: function(a,b) { return a + b; },
  sub: function(a,b) { return a - b; },
  multiply: function(a,b) { return a * b; }
}

在 ES6 之後可以少寫一大堆,像這樣:

const math = {
  add(a,b) { return a + b; },
  sub(a,b) { return a - b; },
  multiply(a,b) { return a * b; }
}

-6- 解構 Destructuring

解構用得好,有益身心健康。

Object destructuring

這段:

function handle(req, res) {
 const name = req.body.name;
 const description = req.body.description;
 const url = req.url;

 log('url endpoint', url);

 // lots of logic happening
 dbService.createPerson( name, description )
}

有點難讀吧,但要從多層深度挖資料,就會寫成這樣。還能怎麼辦?其實有以下妙招喔:

function handle(req, res) {
 const { body: { name, description }, url }, = req;

 log('url endpoint', url);

 // lots of logic happening
 dbService.createPerson( name, description )

變成俐落的一行了。

Array destructuring

不只物件能用,陣列也可以用,像這段:

const array = [1,2,3,4,5,6];

const a = array[0];

const c = array[2];

可以更優雅地改寫成這樣:

const array = [1,2,3,4,5,6];
const [a, ,c, ...remaining] = array;

// remaining = [4,5,6]

上面的模式配對,就可以拆出我們需要的變數。如果要跳過某值,就寫 , , 即可。我另外多寫了一個 rest parameter 來取得其餘資料。

Parameter matching

函數的參數也能這樣寫。當函數有超過 2-3 個參數時,業界慣例常常是這樣寫:

function doSomething(config) {
  if(config.a) { ... }
  if(config.b) { ... }
  if(config.c) { ... }
}

更漂亮的寫法其實是:

function doSomething({ a, b, c }) {
  if(a) { ... }
  if(b) { ... }
  if(c) { ... }
}

-7- 陣列方法

ES6 有大量好用的陣列方法,例如:

  • find(),回傳符合條件的項目,否則回傳 null
  • findIndex(),尋找項目的索引
  • some(), 確認是否包含符合條件的項目
  • includes(), 確認是否包含某個項目

舉例說明如下:

const array = [{ id: 1, checked: true }, { id: 2 }];
arr.find(item => item.id === 2) // { id: 2 }
arr.findIndex(item => item.id === 2) // 1
arr.some(item => item.checked) // true

const numberArray = [1,2,3,4];
numberArray.includes(2) // true

-8- Promises + Async/Await

在只有 callback 能寫的年代,這種寫法很常見:

function doSomething(cb) {
  setTimeout(() =>  {
    cb('done')
  }, 3000)
}

doSomething((arg) => {
 console.log('done here', arg);
})

用來寫非同步任務時,就會這樣寫。但現在我們有 promise 能寫了,所以可以這樣:

function doSomething() {
  return new Promise((resolve, reject) => {
    setTimeout(() =>  {
      resolve('done')
    }, 3000)
  })
}

doSomething().then(arg => {
 console.log('done here', arg);
})

多個流程還能整個串起來,就像這樣:

getUser()
  .then(getOrderByUser)
  .then(getOrderItemsByOrder)
  .then(orderItems => {
    // do something with order items
  })

Async/await

接著還有 async/await 可以用。上方的範例,相關 promise 變成:

async function getItems() {
  try {
    const user = await getUser();
    const order = await getOrderByUser(user);
    const items = await getOrderItemsByOrder(order);
    return items;
  } catch(err) {
    // handle error here, the suggestion to return something or rethrow
  }
}

getItems().then(items => {
  // do something with order items
})

看起來像是同步,但其實非同步的一段程式碼:)

-9- 模塊 Modules

幾乎所有程式語言都支援模塊功能。將程式碼分為多個檔案,各自為獨立單元,就是模塊了。像這樣:

// math.js

export function add(a,b) { return a + b; }
export function sub(a,b) { return a - b; }

export default (a,b) => a * b;

// main.js
import mult, { add, sub } from './math';

mult(2, 4) // 8
add(1,1)   // 2
sub(1,2)   // -1

使用 export 關鍵字來表示 add 跟 sub 是公開可用的。export default 代表不指定函數時直接導入的內容。在 main.js 中,將預設導入命名為 mult,然後指定導入函數 add 和 sub。

-10- 箭頭函數 + this

整篇文章一直在用箭頭函數,其實只是另一種函數的寫法而已。以前要這樣寫:

function printArray(arr) {
 // do something
}

現在可以這樣寫:

const printArray = (arr) => {
 // do something
}

單行函數

函數還可以用一行寫完:

const add = (a,b) => a + b

這種寫法可以省略 return 直接回傳結果。要回傳物件也可以,這樣即可:

const create = (a,b) = > ({ x: a, y: b })

Lexical this

以前常常會搞混 this 代表什麼,舉例來說:

let array = [1,2,3];

function sum() {
  this.total = 0;

  arr.forEach(function(item) {
    this.total+= item;  // `this` is the inner functions `this`, BAD
  })
  return total;
}

這個例子中,this 在 forEach 指錯地方了。以前的解法是:

function sum() {
  this.total = 0;
  var self = this;

  arr.forEach(function(item) {
    self.total+= item;  // now we are using `self`, it solves it but feels hacky
  })
  return total;
}

雖然多寫個 self 變數可以解決,但實在很鳥。新的箭頭函數寫法則解決了這問題:

function sum() {
  this.total = 0;

  arr.forEach((item) => {
    this.total+= item;  // all is well `this` points to outer function
  })
  return total;
}

結論

ES6 之後有很多好東西可以用,今天先介紹一些,希望對大家有幫助!

按讚的人:

共有 0 則留言