Understand the charm of native JavaScript ES6-ES10

Keywords: Javascript Attribute Database

As a front-end development engineer, the blind pursuit of the framework seems to be a bit of a waste of money, to know that the basic skills is the hard core. JavaScript grammar has been updated in recent years. Whether we are the core developers of the framework or business reshapers, it's good to learn the latest JavaScript grammar and capabilities. Let's look at the power of the new grammar with a few small examples.

"Initialize an array, requiring the length of the array to be 5 and the default value of each element to be 0"

This seems to be a very simple question. We might write code like this:

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

But if you have studied ES6 grammar, you will know that Array's new prototype object method has a fill API, which can easily implement this topic. The code is as follows:

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

That's how the new grammar gives JavaScript new capabilities. If we don't keep learning the new grammar, it's hard to write the simplest, most elegant, and best-performing code. Of course, reading other students or open source code is not necessarily able to understand. So what capabilities does ES6 add or enhance? Let's look at the atlas.

It is not clear from this map that ES6 adds many new grammars, such as Class, Generator, Proxy, Iterator, etc. They can solve class, asynchronism, proxy, custom traversal and other functions. Let's look at a small example:

Implementing classes and inheritance.

Before ES6, both classes and inheritance were implemented by functions, and prototype chains were also used in inheritance. The code is as follows:

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

The meaning of this code is to define a component class, which defines an attribute id, which is random and read-only. ES6 has a special grammar to define classes.

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)

It is easier to understand ES6 semantically. Believe it or not, let's look at the writing of inheritance.

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)

Comparing the code above and below, we can see that ES6 is much more comfortable and easier to read. With the help of this question, let's think about whether ES6 can continue to be optimized. For example, the Object.defineProperty method seems so out of place in the constructor. Is there a more elegant way of writing? Why not try ES6's new grammar 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 and lass getter can ensure that the id is read-only and that the id is "random" and "unique" when proxy is instantiated. Some students will say that this code has a loophole, proxy can also be modified will lead to id can also be modified. That's right, but it underestimates proxy's ability. Look again:

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)

You know that proxy can have a lot of the same content as id, so we won't have a definition "read-only" displayed with Object.defineProperty. Write "no trace" in the form of class getter + proxy. Do you enjoy it? Of course, proxy has many uses, such as protecting data, data validation and so on.

If you're not addicted, let's look at a more powerful feature: custom traversal.

"There are many authors of books in our database. These authors are classified according to the categories of books. Now what should we do if we want to traverse all authors?"

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'
    ]
  }
}

We want to be able to traverse authors and get a list of all authors.

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

I wish I could do this, but the browser made a mistake, telling us that authors are not traversable. We can only do this by traversing all key s:

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"]
}

Although implemented in the way of ES5, we still hope to achieve it in the way of for...of, which is simple and convenient. ES6 adds Iterator so that any data structure can implement a custom traversal. Code directly:

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()
      }
    }
  }
}

We only need to add the Iterator traversal interface to the authors data structure to traverse in the way of for...of, and the browser will no longer report errors. Are they amazing? In fact, ES7, ES8, ES9 and ES10 came into being after ES6, which made native JavaScript more powerful.

Not learning new native JavaScript skills is bound to make us miss out on more glamorous cities and learn ES6~ES10 in pairs.

Posted by acroporas on Tue, 24 Sep 2019 07:15:23 -0700