領略原生 JavaScript ES6~ES10 的魅力

圖片描述

作爲前端開發工程師,盲目追逐框架似乎有點捨本逐末,要知道基本功纔是硬核。JavaScript 的語法這幾年一直在更新,不管我們是框架的核心開發者還是業務重塑者,學習下最新的 JavaScript 語法和能力是非常有好處的。下面我們通過幾個小示例來看下新語法的強大之處:

“初始化一個數組,要求數組的長度是 5,每個元素的默認值是 0”

這道題看似非常簡單,我們可能會這樣來寫代碼:

const arr = []
for(let i = 0; i < 5; i++){
  arr.push(0)
}

可是如果你學習過 ES6 的語法,就會知道 Array 新增的原型對象方法上有個 fill 的 API,它可以輕鬆實現這個題目,代碼如下:

const arr = Array(5).fill(0)

這就是新的語法賦予 JavaScript 新的能力,如果我們不持續學習新的語法,寫出來的代碼很難是最簡、最優雅、性能最好。當然,閱讀其他同學或者開源代碼的時候也不一定能看懂。那麼 ES6 到底新增或者增強了哪些能力呢?我們來看下圖譜:

圖片描述

從這個圖譜不能看出 ES6 增加了很多新的語法,比如 Class、Generator、Proxy、Iterator 等。它們可以解決類、異步、代理、自定義遍歷等功能。不如我們再來看個小示例:

實現類與繼承。

在 ES6 之前實現類與繼承都是藉助函數來實現的,在繼承方面也是利用原型鏈。代碼如下:

function Component () {
  this.id = Math.random().toString(36).slice(-5)
  Object.defineProperty(this, 'id', {
    writable: false
  })
}
const com = new Component()
com.id = 3
console.log(com.id) // jklls

這段代碼的含義是定義一個組件類,類定義了一個屬性 id,這個 id 是隨機、只讀的。ES6 有了專門的語法來定義類。

class Component {
  constructor () {
    this.id = Math.random().toString(36).slice(-5)
    Object.defineProperty(this, 'id', {
      writable: false
    })
  }
}
const com = new Component()
com.id = 3
console.log(com.id)

在語義上看 ES6 的寫法更容易讀懂。不信,我們在看下繼承的寫法:

function Component () {
  this.id = Math.random().toString(36).slice(-5)
  Object.defineProperty(this, 'id', {
    writable: false
  })
}
function SubComponent () {
  Component.call(this)
}
SubComponent.prototype = Component.prototype
const com = new SubComponent()
com.id = 3
console.log(com.id)

class Component {
  constructor () {
    this.id = Math.random().toString(36).slice(-5)
    Object.defineProperty(this, 'id', {
      writable: false
    })
  }
}

class SubComponent extends Component {

}
const com = new SubComponent()
com.id = 3
console.log(com.id)

上下代碼對比可以看出來 ES6 的方式要舒服很多,也更容易閱讀。藉助這個題我們再來思考 ES6 這個寫法還能繼續優化嗎?比如 Object.defineProperty 方法在構造函數裏顯得那麼格格不入。有沒有更優雅的寫法呢?不妨試試 ES6 新的語法 Proxy?

class Component {
  constructor () {
    this.proxy = new Proxy({
      id: Math.random().toString(36).slice(-5)
    }, {})
  }
  get id () {
    return this.proxy.id
  }
}
const com = new Component()
com.id = 3
console.log(com.id)

利用 Proxy 和 Class getter 方式就能保證 id 是隻讀的,在 proxy 實例化的時候也能保證 id “隨機”、“唯一”。有同學會說這個代碼有漏洞,proxy 還可以修改會導致 id 也可以被修改。說的沒錯,但是低估了 proxy 的能力,你再看:

class Component {
  constructor () {
    this.proxy = new Proxy({
      id: Math.random().toString(36).slice(-5)
    }, {
      set (target, key, value) {
        return false
      }
    })
  }
  get id () {
    return this.proxy.id
  }
}
const com = new Component()
com.proxy.id = 4
com.id = 3
console.log(com.id)

要知道 proxy 下面可以放很多跟 id 一樣的內容,這樣我們就不會一個一個用 Object.defineProperty 去顯示的定義“只讀”。用 class getter + proxy 的方式寫起來“不露痕跡”,大家是否享受這種寫法呢?當然,proxy 還有很多用武之地,比如把保護數據、數據校驗等等。

如果大家沒過癮,我們再看一個更強大的功能:自定義遍歷。

“我們數據庫裏存放着很多圖書的作者,這些作者按照圖書的類別進行分類,現在想遍歷所有作者該怎麼辦?”
let authors = {
  allAuthors: {
    fiction: [
      'Agatha Christie',
      'J. K. Rowling',
      'Dr. Seuss'
    ],
    scienceFiction: [
      'Neal Stephenson',
      'Arthur Clarke',
      'Isaac Asimov',
      'Robert Heinlein'
    ],
    fantasy: [
      'J. R. R. Tolkien',
      'J. K. Rowling',
      'Terry Pratchett'
    ]
  }
}

我們希望可以對 authors 進行遍歷並得到所有作者的名單。

for (let author of authors) {
  console.log(author)
}

本希望可以這做可是瀏覽器報錯了,告訴我們 authors 是不可遍歷的。那我們只能通過遍歷所有 key 的方式來實現:

for (let key in authors) {
  let r = []
  for (let k in authors[key]) {
    r = r.concat(authors[key][k])
  }
  console.log(r)
  // ["Agatha Christie", "J. K. Rowling", "Dr. Seuss", "Neal Stephenson", "Arthur Clarke", "Isaac Asimov", "Robert Heinlein", "J. R. R. Tolkien", "J. K. Rowling", "Terry Pratchett"]
}

雖然用 ES5 的方式實現了,可是我們仍希望用 for...of 的方式來實現,簡單便捷。ES6 增加了 Iterator 讓任意數據結構可以實現自定義遍歷器。直接上代碼:

authors[Symbol.iterator] = function () {
  let allAuthors = this.allAuthors
  let keys = Reflect.ownKeys(allAuthors)
  let values = []
  return {
    next () {
      if (!values.length) {
        if (keys.length) {
          values = allAuthors[keys[0]]
          keys.shift()
        }
      }
      return {
        done: !values.length,
        value: values.shift()
      }
    }
  }
}

我們只需要對 authors 這個數據結構增加 Iterator 遍歷器接口即可用 for...of 的方式來遍歷了,瀏覽器不再報錯了。有沒有很驚豔?其實 ES6 之後 ES7、ES8、ES9、ES10相繼誕生,它們讓原生 JavaScript 的能力再次提升。

圖片描述

不學習原生 JavaScript 新技能註定會讓我們錯過更多魅力之城,一起結對學 ES6~ES10。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章