ECMAScript 新特性(三)

109 阅读2分钟

image.png

for...of

基本用法

const arr = [100, 200, 300, 400]

for (const item of arr) {
  console.log(item)
  if (item > 100) {
    break // 通过break进行终止循环
  }
}

相比forEach,可通过break进行终止循环,而forEach不能通过break中断循环

遍历Set和Map

// 遍历Set
const s = new Set(['foo', 'bar'])

for (const item of s) {
  console.log(item)
}
// 遍历Map
const m = new Map()
m.set('foo', '123')
m.set('bar', '345')

for (const [key, value] of m) {
  console.log(key, value)
}

输出
foo 123
bar 345

缺点

  • 不能遍历普通对象
  • 必须实现iterator接口才可以被for...of遍历
const obj = { foo: 123, bar: 456 }

for (const item of obj) {
  console.log(item)
}
// 报错 TypeError: obj is not iterable

可迭代接口iterator

for...of内部的原理:

通过调用被遍历对象的iterator方法得到一个迭代器从而去遍历内部的数据

const set = new Set(['foo', 'bar', 'baz'])

const iterator = set[Symbol.iterator]()

console.log(iterator.next())  // { value: 'foo', done: false }
console.log(iterator.next())  // { value: 'bar', done: false }
console.log(iterator.next())  // { value: 'baz', done: false }
console.log(iterator.next())  // { value: undefined, done: true }

普通对象实现迭代器

const obj = {
  store: ['foo', 'bar', 'baz'],

  [Symbol.iterator]: function () {
    let index = 0
    const self = this

    return {
      next: function () {
        const result = {
          value: self.store[index],
          done: index >= self.store.length
        }
        index++
        return result
      }
    }
  }
}

for (const item of obj) {
  console.log('循环体', item)
}

对外实现统一遍历接口

const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],

  // 提供迭代器(ES2015 统一遍历访问接口)
  [Symbol.iterator]: function () {
    const all = [...this.life, ...this.learn, ...this.work]
    let index = 0
    return {
      next: function () {
        return {
          value: all[index],
          done: index++ >= all.length
        }
      }
    }
  }
}

for (const item of todos) {
  console.log(item)
}

生成器(惰性执行)

语法(也实现了iterator接口)

function * foo () {
  yield 100
  yield 200
  yield 300
}

const generator = foo()

console.log(generator.next()) // 遇到第一个 yield 暂停 { value: 100, done: false }
console.log(generator.next()) //遇到下一个 yield 再次暂停 { value: 200, done: false }
console.log(generator.next()) // { value: 300, done: false }
console.log(generator.next()) // { value: undefined, done: true }

基本用法

  • 发号器
function * createIdMaker () {
  let id = 1
  while (true) {
    yield id++
  }
}
const idMaker = createIdMaker()

console.log(idMaker.next().value) // 1
console.log(idMaker.next().value) // 2
console.log(idMaker.next().value) // 3
console.log(idMaker.next().value)  // 4
  • 使用 Generator 函数实现 iterator 方法
const todos = {
  life: ['吃饭', '睡觉', '打豆豆'],
  learn: ['语文', '数学', '外语'],
  work: ['喝茶'],
  [Symbol.iterator]: function * () {
    const all = [...this.life, ...this.learn, ...this.work]
    for (const item of all) {
      yield item
    }
  }
}

for (const item of todos) {
  console.log(item)
}

ES2016新增特性

includes

可检测包含NaN

const arr = ['foo', 1, NaN, false]
console.log(arr.indexOf(NaN) // false
console.log(arr.includes(NaN) // true

指数运算符

2 ** 10  等同于  Math.pow(2, 10)

ES2017新增特性

Object.values()

const obj = {
    foo: 'value1',
    bar: 'value2'
}
console.log(Object.values(obj));  // [ 'value1', 'value2' ]

Object.entries()

for (const [key, value] of Object.entries(obj)) {
    console.log(key, value);
}
输出
foo value1
bar value2

Object.getOwnPropertyDescriptors()

  • 复制完整的数据信息
const p1 = {
    firstName: 'Lei',
    lastName: 'Wang',
    get fullName () {
        return this.firstName + ' ' +  this.lastName
    }
}
console.log(p1.fullName);
const p2 = Object.assign({}, p1) // 会将fullName当做普通对象来复制
p2.firstName = 'zce'
console.log(p2.fullName);  // Lei Wang

const descriptors = Object.getOwnPropertyDescriptors(p1) // 复制完整的信息
const p2 = Object.defineProperties({}, descriptors)
p2.firstName = 'zce'
console.log(p2.fullName); // zce Wang

padEnd/padStart

  • 给定的字符串去填充目标字符串的开始或者结尾直到达到指定的长度
  • padEnd(长度, 给定的字符串)
const books = {
    html: 5,
    css: 16,
    javascript: 128
}
for (const [name, count] of Object.entries(books)) { 
    console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, 0)}`);
}
输出:
html------------|005
css-------------|016
javascript------|128

Async/Await(后续补充)