ES6 常用語法和開發總結(萬字長文)


ES6 常用語法和開發總結

前言

阮一峯老師的 ES6 入門教程 看了好幾遍,發現每次看完都感覺有很多地方不懂,越看越焦慮,現在稍微明白了,這可能是大多數人追求的完美主義,希望每件事情都搞懂心理才踏實。其實,是沒必要的,根據”二八定律“,我們只要掌握其中的 20% 常用知識和語法去解決開發中的 80% 問題就夠了,剩下不懂的地方可以通過閱讀相關文檔和資料解決。更重要的原因是前端技術更新迭代如此之快,我們也要跟上步伐,把有限的時間放在正確的事情上,更何況我們還有詩和遠方。所以在這裏總結一下 ES6 常用語法和開發過程中遇到的一些坑,然後繼續前行。

let 聲明 VS const 聲明

相同點

  • 沒有變量提升,必須先聲明後使用,否則報錯
  • 形成塊級作用域,暫時性死區
  • 不能重複聲明
  • 在全局聲明,不能掛載在window上

不同點

  • const 聲明變量時需要賦初始值
  • const 聲明的基本類型數值不能被修改,聲明的引用類型可以修改屬性,但是不能重新賦值改變引用的地址
  • 使用 const 程序執行效率更快

console.log(a) // 報錯,Uncaught ReferenceError: a is not defined
let a = 1
let a = 2 // 報錯,Uncaught SyntaxError: Identifier 'a' has already been declared

if (true) { // 形成塊級作用域
  var b = 33
  let c = 22
}
console.log(b) // 33
console.log(c) // Uncaught ReferenceError: c is not defined

var name = '張三'
let lisi = '李四'
console.log(window.name) // 張三
console.log(window.lisi) // undefined

const d = '11'
const obj = {name: 33}

d = '22' // Uncaught TypeError: Assignment to constant variable.
obj.name = '2323' // {name: 2323}
obj = {} // Uncaught TypeError: Assignment to constant variable

解構賦值

  • 數組解構賦值
  • 對象解構賦值
  • 字符串解構賦值
  • 函數參數解構賦值

解構賦值使用場景

  • 交換變量的值
  • 從函數返回多個值
  • 函數參數解構
  • 提取 JSON 數據
  • 遍歷 Map 結構
  • 模塊導入解構
let x = {
  name: 33
}
ley y = [33, 22]

//交換值
[x, y] = [y, x]
console.log(x) // [33, 22]

function fn() {
  ...
  return {name, value}
}

const {name, value} = fn() // 提取函數多個返回值

function getValue({name, value, ...}) { // 參數解構賦值
  ...
  return value
}

let {name, data } = {name, '33', value: 22, data: [3, 2, 4]} //對象解構賦值,提取 JSON數據

function fn () {
   for(let [k, v] of map.entries()) { // [k, v] map 解構賦值
      ...
   }
}

import {module1, module2, ... } from './filename.js' // 模塊解構賦值

注意事項

  • 解構賦值變量重命名。有時候我們需要轉換一下後臺返回的鍵名,這時這個地方用的上

  • 函數參數對象解構賦值時,我們需要給它默認值,這時如果調用函數不傳對象就會報錯,解決方法是初始化一個空對象


let {x: width, y: height} = {x: '220px', y: '100px'}  // 重命名
console.log(width, height) // 220px 100px

function fn ({name='', value=0}) {
  ...
}
fn() // Uncaught TypeError: Cannot read property 'name' of undefined

// 加一個空對象
function fn ({name='', value=0} = {}) {
  ...
}

字符串新增方法

  • includes:返回布爾值,判斷字符串是否包含某串字符。接受兩個參數,第二個參數是起始的位置

  • startsWith:返回布爾值,判斷字符串開頭是否包含某串字符

  • endsWith:回布爾值,判斷字符串結尾是否包含某串字符

  • repeat:返回一個新的字符串,將原字符串重複 n 次

  • padStart:返回新的字符串,在字符串前面補全,接受兩個參數,第一個參數補全字符串長度,第二個參數補全的字符

  • padEnd::返回新的字符串,在字符串後面補全,接受兩個參數,第一個參數補全字符串長度,第二個參數補全的字符

  • trimStart:去除前面空格

  • tiemEnd:去除後面空格

  • matchAll: 返回一個正則表達式在當前字符串的所有匹配


let str = 'abcdef'
str.includes('bc') // true
str.includes('ss') // false

str.repeat(2) // "abcdefabcdef"
str.repeat(0) // ''
str.repeat(-1) // 報錯,Uncaught RangeError: Invalid count value

str.padStart(10, 1) // "1111abcdef"
str.padEnd(10, 0) // "abcdef0000"

正則表達式

方法

  • match:匹配成功返回數組,匹配不成功返回null

  • replace:替換字符串,返回一個新的字符串

  • search:匹配返回第一個索引的位置,匹配不成功返回 -1

  • split:返回數組

  • exec:匹配成功返回數組,匹配不成功返回null

  • test:返回布爾值 boolean

數值擴展

方法

  • Number.isInteger:判斷是否是整數
  • Number.isSafeInteger:判斷是否是安全整數
  • Number.isNaN
  • Math.trunc():去除一個數的小數部分

函數

函數拓展

  • 函數默認參數

  • rest 參數

  • 函數 length 屬性。它表示函數參數的個數,如果參數設置默認值,則 length 減 1;rest 參數也不會計入 length 屬性

  • 箭頭函數注意事項

    • 函數體內的 this 對象,就是定義時所在的對象
    • 箭頭函數不可以當作構造函數使用,不可以使用 new 命令
    • 不可以使用 arguments 對象
    • 不可以使用 yield 命令
    • 箭頭函數不適合使用場景:1、定義對象的方法;2、監聽事件回調
  • 尾調用優化

  • 尾遞歸


function fn(a, b, c) {
...
}
fn.leng // 3

function fn(a, b=1, c=2) {
...
}
fn.leng // 1

let obj = {
  name: 'JEFFER',
  getName: () => { // 不適合箭頭函數
  console.log(this.name)
}
obj.getName() // undefined

doc.addEventListener('click', () => {
  console.log(this) // 這裏的this原本指向dom元素,現在使用箭頭函數指向了 window
}

數組

  • from:將 ArgumentsDOM 元素集合等僞數組,轉化爲數組

  • of:將多個數據項向轉化爲數組

  • find:查找元素,查找成功返回數組元素,查找不到返回 null

  • findIndex:查詢下標,查找成功返回數組元素下標,查找不到返回 -1

  • copyWithin:數組內部複製

  • fill:填充數組

  • entries:返回數組下標和元素組成的二維數組

  • keys:返回下標的數組

  • values:返回元素的數組

  • includes:匹配數組項,返回 boolean

  • flat: 數組降維

function fn(a, b,c) {
...
console.log(Array.from(Arguments)) // [a, b, c]
}
Array.of(1, 2, 3) // [1, 2, 3]

let arr = [22, 33, 44, 55]
arr.find((item) => item === '33') //33 
arr.findIndex((item) => item === '33') // 1

數組迭代方法

數組迭代方法在函數式編程時非常有用,熟練使用函數式編程能大大提高自己的編程效率,寫出的代碼也很簡潔,易讀易維護

  • forEach:遍歷數組,中間可以使用 continue 跳過本次循環,在循環中break 關鍵字是不生效的

  • filter:過濾數組返回一個新數組,不改變原數組。可以進行鏈式操作

  • map:數組映射,返回一個數組,不改變原數組。可以進行鏈式操作

  • reduce:數組彙總,返回一個值。接收兩個參數,第二個參數接收默認值

  • every:返回一個 boolean 值,遍歷結果全部爲 true 才爲 true,否則返回 false

  • some:返回一個 boolean 值,遍歷某次結果返回 true時會立刻結束循環。這個想中間結束循環很有用,不用再借助 break 結束循環,有利於提高執行效率


let arr = [32,32,2324, 223]

arr.forEach((item, index) => {
  if (...) {
    continue // 滿足條件想盡早結束本次循環
   }
})

arr.filter((item, index) => {
  ...
  return item
}).filter(()=>{...}).map(()=>{...}) // 鏈式操作

arr.map((item, index) => {
  ...
  return item
}).filter(()=>{...}).map(()=>{...}) // 鏈式操作

arr.reduce((pre, next) { // 彙總
  ...
  return item
}, [])

arr.ervery((pre, next) {
  ...
  return item
})

arr.some((pre, next) {
  if (...) {
    ...
    return true // 結束循環
  }
  ...
  return item
})

對象

方法

  • Object.assign():合併對象,淺拷貝,改變原對象

  • Object.keys():返回數組,獲取對象的鍵

  • Object.values():返回數組,獲取對象的值

  • Object.entries():返回二維數組,獲取對象的鍵值

  • Object.fromEntries():將二維數組或 map 數據類型轉化爲對象

  • Object.create():創建對象

  • Object.is():同值相等,NaN等於NaN, 0 不等於 -0

  • Object.getPrototypeOf(obj):獲取對象原型

  • Object.setPrototypeOf(obj):設置對象原型

Object.entries()Object.fromEntries() 方法可以相互轉換

Object.fromEntries特殊用法,配合 URLSearchParams 對象,將查詢字符串轉爲對象


le obj = { name: '33' }
Object.assign(obj, {value: 11}) // 注意,改變了原對象obj
console.log(obj) // {name, '33', value: 11}

// 二維數組轉對象 { foo: "bar", baz: 42 }
Object.fromEntries([ 
  ['foo', 'bar'],
  ['baz', 42]
]) 

// map 轉對象
const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);
Object.fromEntries(entries) // { foo: "bar", baz: 42 }

// 將 URL 參數轉化爲對象
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }

Set 和 Map 數據結構

Set

Set 類似於數組結構,存放唯一值

屬性

  • Set.prototype.constructor :構造器
  • Set.prototype.sizeSet實例的成員總數

方法

  • Set.prototype.add(value):添加某個值,返回 Set 結構本身。
  • Set.prototype.delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • Set.prototype.has(value):返回一個布爾值,表示該值是否爲Set的成員。
  • Set.prototype.clear():清除所有成員,沒有返回值。

s.add(1).add(2).add(2);
// 注意2被加入了兩次

s.size // 2

s.has(1) // true
s.has(3) // false

s.delete(2);
s.has(2) // false

迭代方法

  • Set.prototype.keys():返回鍵名的遍歷器
  • Set.prototype.values():返回鍵值的遍歷器
  • Set.prototype.entries():返回鍵值對的遍歷器
  • Set.prototype.forEach():使用回調函數遍歷每個成員

let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// 這樣也行
for (let item of set) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

set.forEach((value, key) => console.log(key + ' , ' + value))
// "red", "red"
// "green", "green"
// "blue", "blue"

使用場景

  • 可以用來去重,數組去重、字符串去重
  • 實現並集、交集、差集

// 去除數組的重複成員
[...new Set(array)]

// 去除字符串中重複字符
[...new Set('ababbc')].join('')
// "abc"
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

// 並集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}

// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}

注意事項

  • 添加 Set 集合數據區分數據類型,5“5” 兩個值不一樣
  • SetNaN 是相等的,多次添加只添加一個
  • 兩個對象總不相等
  • SetArray 可以相互轉換

let set = new Set()
set.add(5)
set.add('5')
set.add(NaN)
set.add(NaN)
set.add({})
set.add({})
set.size // 5

// set 最終結果是
// Set(5) {5, "5", NaN,{},{}}

// 數組轉 Set
let set1 = new Set(arr)

// Set 轉數據
let arr = [...set]
// 或者
let arr = Array.from(set)

Map

Map 類似於對象結構,本質上是鍵值對,簡稱 Hash 結構

屬性

  • Map.prototype.constructor :構造器
  • Map.prototype.sizeMap實例的成員總數

方法

  • Map.prototype.set(key, value):添加某個鍵值對,返回 整個Map 結構。如果key已經有值,則鍵值會被更新,否則就新生成該鍵。(添加多個可以進行鏈式操作)

  • Map.prototype.get(key):讀取key對應的鍵值,如果找不到key,返回undefined

  • Map.prototype.has(key):返回一個布爾值,表示某個鍵是否在當前 Map 對象之中

  • Map.prototype.delete(key):刪除某個鍵,返回true。如果刪除失敗,返回false

  • Map.prototype.clear():清除所有成員,沒有返回值。

迭代方法

用法和 Set 一樣,就不粘貼代碼了

  • Map.prototype.keys():返回鍵名的遍歷器

  • Map.prototype.values():返回鍵值的遍歷器

  • Map.prototype.entries():返回鍵值對的遍歷器

  • Map.prototype.forEach():使用回調函數遍歷每個成員,forEach 可以接受第二個參數用來綁定 this 執行上下文

Map 和數組的轉換

數組給我們提供了豐富的 API,將 Map 結構轉換爲數組處理數據更方便


const map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');

[...map.keys()]
// [1, 2, 3]

[...map.values()]
// ['a', 'b', 'c']

[...map] or [...map.entries] 
// [[1,'a'], [2, 'b'], [3, 'c']]

const map1 = new Map(
  [...map].filter(([k, v]) => k < 3)
);
// 產生 Map 結構 {1 => 'a', 2 => 'b'}

const map2 = new Map(
  [...map].map(([k, v]) => [k * 2, '_' + v])
    );
// 產生 Map 結構 {2 => '_a', 4 => '_b', 6 => '_c'}

Proxy 攔截器

  • get(target, propKey, receiver):攔截對象屬性的讀取,比如proxy.fooproxy['foo']

  • set(target, propKey, value, receiver):攔截對象屬性的設置,比如proxy.foo = vproxy['foo'] = v,返回一個布爾值。

  • has(target, propKey):攔截propKey in proxy的操作,返回一個布爾值。

  • deleteProperty(target, propKey):攔截delete proxy[propKey]的操作,返回一個布爾值。

  • ownKeys(target):攔截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循環,返回一個數組。該方法返回目標對象所有自身的屬性的屬性名,而Object.keys()的返回結果僅包括目標對象自身的可遍歷屬性。

  • getOwnPropertyDescriptor(target, propKey):攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對象。

  • defineProperty(target, propKey, propDesc):攔截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一個布爾值。

  • preventExtensions(target):攔截Object.preventExtensions(proxy),返回一個布爾值。

  • getPrototypeOf(target):攔截Object.getPrototypeOf(proxy),返回一個對象。

  • isExtensible(target):攔截Object.isExtensible(proxy),返回一個布爾值。

  • setPrototypeOf(target, proto):攔截Object.setPrototypeOf(proxy, proto),返回一個布爾值。如果目標對象是函數,那麼還有兩種額外操作可以攔截。

  • apply(target, object, args):攔截 Proxy 實例作爲函數調用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)

  • construct(target, args):攔截 Proxy 實例作爲構造函數調用的操作,比如new proxy(...args)

Reflect

ReflectES6 爲了操作對象而提供的新 API

每個新東西的出現都是爲了解決實際問題,Reflect 的出現同樣也是爲了解決以下問題:

  • 修改某些Object方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false

  • Object操作都變成函數行爲。某些Object操作是命令式,比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)讓它們變成了函數行爲。

  • Reflect對象的方法與Proxy對象的方法一一對應,只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法

方法

  • Reflect.apply(target, thisArg, args):等同於Function.prototype.apply.call(func, thisArg, args),用於綁定this對象後執行給定函數

const ages = [11, 33, 12, 54, 18, 96];

// 舊寫法
const youngest = Math.min.apply(Math, ages);

// 新寫法
const youngest = Reflect.apply(Math.min, Math, ages);
  • Reflect.construct(target, args):等同於new target(...args),這提供了一種不使用new,來調用構造函數的方法。

  • Reflect.get(target, name, receiver):獲取對象的值,例如 target[name], receiver 參數可以修改讀取this 上下文(後面一樣,就不介紹了)

  • Reflect.set(target, name, value, receiver):設置對象的值 target[name] = value

  • Reflect.defineProperty(target, name, desc):相當於

  • Reflect.deleteProperty(target, name):等同於delete target[name],用於刪除對象的屬性

  • Reflect.has(target, name):等同於name in target裏面的in運算符

  • Reflect.ownKeys(target):等同於Object.keys(target)

  • Reflect.isExtensible(target):等同於Object.isExtensible(target)

  • Reflect.preventExtensions(target):等同於Object.preventExtensions(target)

  • Reflect.getOwnPropertyDescriptor(target, name):等同於Object.getOwnPropertyDescriptor(target)

  • Reflect.getPrototypeOf(target):等同於Object.getPrototypeOf(target)

  • Reflect.setPrototypeOf(target, prototype):等同於Object.setPrototypeOf(target)

Promise

promise 是實現異步編程的一種解決方案,可以通過鏈式操作,解決回調地獄的問題

使用場景

  • 加載圖片
  • 封裝 ajax 請求接口

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

封裝ajax請求接口


const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯了', error);
});

方法

  • Promise.prototype.thenfullfilled 成功狀態之後的回調函數

  • Promise.prototype.catch():發生錯誤時的回調函數

  • Promise.prototype.finally():該方法是 ES2018 引入標準,不管是成功或失敗都會執行

  • Promise.all():用於將多個 Promise 實例,包裝成一個新的 Promise 實例,

const p = Promise.all([promise1, promise2, promise3]).then(res => {});

上面promise1promise2promise3 都是Promise 實例,它們都是成功之後才能執行 then 回調函數,返回參數 res 是個數組,可以用來解決同時請求多個接口

  • Promise.race():和上面的 all 方法用法一樣,不同的地方在於只要有一個實例執行成功,它就成功了,只要有一個失敗它也代表失敗了

  • Promise.allSettled():該方法和上面allrace 用法一樣,它主要解決的是不管成功或失敗都返回,狀態總是fulfilled,不會變成rejected,該方法由 ES2020 引入,有時候,我們不關心異步操作的結果,只關心這些操作有沒有結束。這時,它就很有用

  • Promise.any():和 race 很相似,不同的地方,是不會因爲某個 Promise 變成rejected狀態而結束,有點類似於數組中的 Array.prototype.some 方法,該方法目前是一個第三階段的提案

  • Promise.resolve()Promise 的靜態方法,它的使用場景是將現有對象轉爲 Promise 對象,返回fullfilled成功狀態

  • Promise.reject()Promise 的靜態方法,它的使用場景是將現有對象轉爲 Promise 對象,返回rejected失敗狀態

Async 函數

async 函數也是異步編程的一種解決方案,它和 Promise 不同在於可以使用同步的編碼方式實現異步編程,除此之外使用它代替 Promise 多次調用 then 方法也會使代碼更容易讀懂和解耦

async 函數是 Generator 函數的語法糖,它在此基礎上做了幾點改進:

  • 內置執行器:async函數自帶執行器

  • 更好的語義:asyncawait,比起星號和yield,語義更清楚了

  • 更廣的適用性:async函數的await命令後面,可以是 Promise 對象和原始類型的值(數值、字符串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)。

  • 返回值是 Promise:可以用then方法指定下一步的操作

async函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖

基本用法

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

使用場景

  • 函數聲明可以使用
  • 函數表達式可以使用
  • 對象方法可以使用
  • Class 方法可以使用
  • 迭代數組或對象中使用
  • 併發請求接口數據
// 函數聲明
async function foo() {}

// 函數表達式
const foo = async function () {};

// 對象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// 迭代數組
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}

// 雙重 async/await 併發請求接口數據
async function logInOrder(urls) {
  // 併發讀取遠程URL
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  // 按次序輸出
  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}

Class

class 是一個語法糖,它本身指向一個構造函數

使用場景

  • 使用 class 可以實現面向對象編程
  • 可以使用 extends 繼承,實現抽象和代碼複用
  • 可以定義內部屬性和靜態方法,實現封裝

Module 模塊

作用

模塊的作用是可以將一個大的程序拆分成相互依賴的小文件,再用簡單的方法拼接起來,可以讓程序代碼更容易維護、擴展功能、閱讀和調試。

ES6 VS 其他模塊

  • CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
  • CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。

注意

  • ES6 引入的是隻讀操作,最好不要修改它的值

基本用法

  • export 命令輸出,後面必須是var, let, const 聲明的變量、函數或對象

  • export default 輸出,後面可以是函數、對象或其他數據類型值,不能有var, let, const 關鍵字,並且一個文件只能有一個 export default

  • import 命令輸入, export 輸出的要加大括號,export default 輸出的不用加大括號

// a.js
var name = 33
export name; // 報錯
export var firstName = 'Michael'; // 正確
export default name // 正確

function fn () {}
export fn; // 報錯
export default fn 正確
export function fn () {} // 正確
export default function fn () {} // 正確

export { // 正確
  name as other, // 重命名
  firstName
}

export default { // 正確
  name,
  firstName
}

//-----------------------

// b.js 文件
import { name as username } from './a.js' // export 導出的、重命名
import * as all from './a.js' // 導入所有
import name fromm './a.js // export default 導出的

import() 函數
ES2020提案 引入import()函數,支持動態加載模塊,import()函數可以用在任何地方,不僅僅是模塊,非模塊的腳本也可以使用。它是運行時執行,也就是說,什麼時候運行到這一句,就會加載指定的模塊

編程風格

塊級作用域

  • 聲明變量用 let 代替 var,形成塊級作用域,沒有副作用
  • letconst 優先使用 constconst 聲明常量,減少由於修改值出錯,同時有利於提高程序的運行效率

解構賦值

  • 從數組、對象中提取值時使用解構賦值
  • 函數參數對象使用解構賦值
  • 函數返回對象使用解構賦值

函數

  • 能使用箭頭函數的地方儘量使用箭頭函數
  • 使用函數式編程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章