ES6高级

72 阅读3分钟
迭代器(iterator)

迭代器是数据结构遍历的一种机制,为数据结构定义了统一的遍历规则。

for...of遍历数据方法是通过迭代器去实现的,当一种数据没有实现迭代器接口,使用for...of会抛出异常。

  1. 迭代器在被调用时,返回一个指针对象,指针对象包含一个next()方法,每次调用next()方法时都会返回一个代表当前成员的对象,这个对象包含value和done两个属性。
  2. 迭代器对象有next()、return()、throw()三个属性方法,next()是必要属性。
  3. 自己实现迭代器只要给数据结构或者对象添加[Symbol.iterator]属性即可,其值必须是函数,返回一个指针对象。

手写迭代器

 // 实现对象迭代器
 Object.prototype[Symbol.iterator] = function () {
   const that = this
   let keys = Object.keys(that)
   let keyIndex = 0
   return {
     next() {
       if (keys.length === 0 || keyIndex >= keys.length) {
         return {
           value: undefined,
           done: true,
         }
       }
       const key = keys[keyIndex]
       value = [key, that[key]]
       keyIndex += 1
       return {
         value,
         done: false,
       }
     },
   }
 }
 const obj = { name: 'jack', age: 16 }
 for (let [key, value] of obj) {
   console.log(key, value)
 }
 ​
 // 实现数字迭代器
 Number.prototype[Symbol.iterator] = function () {
   let that = +this,
     i = that < 0 ? that : 0
   that = that < 0 ? 0 : that
   return {
     next() {
       if (i <= that) {
         const value = i
         i++
         return {
           value,
           done: false,
         }
       }
       return {
         done: true,
       }
     },
   }
 }
 for (const n of 5) {
   console.log(n)
 }
 console.log([...5]) // 数组拓展运算符也用到迭代器
 ​
手写Promise
  1. Promise使用的是观察者模式实现,then收集依赖 => 异步触发resolve => resolve执行依赖
  2. Promise A+规范,Promise是状态机,三种状态:padding、fulfilled、rejected,且只能有两种状态转变:padding => fulfilled 或 padding => rejected;then方法接收两个参数,分别对应的是成功失败的回调,then返回的是promise,并且then方法可以被调用多次。
  3. 值穿透:当then()接收的参数不是函数时应该忽略,如果没有忽略,当then()回调不为function时将会抛出异常,导致链式调用中断
  4. 处理状态为fulfilled和rejected时的问题,对于状态已变更的直接执行then回调
  5. 兼容同步任务
const PADDING = 'padding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    this._status = PADDING
    this._value = undefined
    this._resolveQueue = []
    this._rejectQueue = []

    // _resolve 和 _reject 是在 executor 内部调用,使用箭头函数确定this指向
    const _resolve = (val) => {
      // 把resolve执行回调的操作封装成一个函数,放进setTimeout里,以兼容executor是同步代码的情况
      const run = () => {
        if (this._status !== PADDING) return
        this._status = FULFILLED
        this._value = val

        // 这里用一个队列来储存回调,是为了实现规范要求then方法可以被一个promise调用多次
        while (this._resolveQueue.length) {
          const callback = this._resolveQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    const _reject = (val) => {
      const run = () => {
        if (this._status !== PADDING) return
        this._status = REJECTED
        this._value = val

        while (this._rejectQueue.length) {
          const callback = this._rejectQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    // new Promise时立即执行executor,并传入resolve和reject
    executor(_resolve, _reject)
  }

  then(resolveFn, rejectFn) {
    typeof resolveFn !== 'function' ? (resolveFn = (value) => value) : null
    typeof rejectFn !== 'function'
      ? (rejectFn = (reason) => {
          throw new Error(reason instanceof Error ? reason.message : reason)
        })
      : null

    return new MyPromise((resolve, reject) => {
      // 把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
      let fulfilledFn = (value) => {
        try {
          let res = resolveFn(value)
          res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
        } catch (error) {
          reject(error)
        }
      }
      let rejectedFn = (err) => {
        try {
          let res = rejectFn(err)
          res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
        } catch (error) {
          reject(error)
        }
      }

      switch (this._status) {
        case PADDING:
          this._resolveQueue.push(fulfilledFn)
          this._rejectQueue.push(rejectedFn)
          break
        case FULFILLED:
          fulfilledFn(this._value)
          break
        case REJECTED:
          rejectedFn(this._value)
          break
      }
    })
  }

  catch(rejectFn) {
    return this.then(undefined, rejectFn)
  }

  finally(callback) {
    return this.then(
      (value) => MyPromise.resolve(callback()).then(() => value),
      (reason) =>
        MyPromise.reject(callback()).then(() => {
          throw reason
        })
    )
  }

  static resolve(val) {
    if (val instanceof Promise) val
    return new Promise((resolve, reject) => {
      resolve(val)
    })
  }

  static reject(reason) {
    return new Promise((resolve, reject) => reject(reason))
  }

  static all(promises) {
    let count = 0
    const result = []
    return new MyPromise((resolve, reject) => {
      promises.forEach((p, i) => {
        MyPromise.resolve(p).then(
          (val) => {
            count++
            result[i] = val
            if (count === promises.length) resolve(result)
          },
          (err) => reject(err)
        )
      })
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach((p) => {
        MyPromise.resolve(p).then(resolve).catch(reject)
      })
    })
  }
}

这篇文章用来记录ES6高级相关的面试题,之后会陆续更新~