promise、数组扁平化、设计模式

88 阅读6分钟

Promise 的其他方法

  • 总代码:
 function fn() {
            const p = new Promise(function (reslove, reject) {
                const timer = Math.ceil(Math.random() * 3000) + 2000
                setTimeout(() => {
                    if (timer > 3500) {
                        reject('失败')
                    } else {
                        reslove('成功')
                    }
                }, timer)
​
            })
            return p
        }
  • promise实例化对象 还有一个方法
  • finally-----不管成功失败都会执行
  • /**
            * promise 实例化对象 还有一个方法
           */
           fn().then(res => {
               console.log('成功了: ', res)
           }).catch(res => {
               console.log('失败了: ', res)
           }).finally(res => {
               console.log('不管成功还是失败, 一定会执行, 然后我现在把 loadding 图片关闭')
           })
      
    
  • Promise构造函数上也有一些方法

    1. all接受一个数组,数组内可以传递多个promise对象

      • all方法的状态取决数组内部的promise对象的状态
      • 如果都成功,all方法也是成功
      • 如果有一个失败,all方法就是失败
      • Promise.all([fn(), fn(), fn()])
                    .then(res => {
                        console.log('如果我输出, 代表所有 promise 对象都是成功状态')
                    })
                    .catch(res => {
                        console.log('如果我输出, 代表最少有一个 promise 状态为失败状态')
                    })
        
    2. race接受一个数组,数组内可以传递多个promise对象

      • race方法的状态取决于数组内部的promise对象中第一个结束的

      • 如果第一个结束时是成功,race就是成功

      • 如果第一个结束时是失败,race就是失败

      • Promise.race([fn(), fn(), fn()])
                  .then(res => {
                      console.log('如果我执行, 代表 数组内第一个结束的 promise状态为成功')
                  })
                  .catch(res => {
                      console.log('如果我执行, 代表 数组内第一个结束的 promise状态为失败')
                  })
          
        
      1. allSettled接受一个数组,数组内可以传递多个promise

      • 他只执行 .then,接收到的参数是一个数组形式的,内部元素为对应的promise的状态
      • Promise.allSettled([fn(), fn(), fn(), fn()])
                    .then(res => {
                        console.log(res)
                    })
        
  • 强行返回一个成状态
  • Promise.resolve()   // 4. 强行帮我们返回一个成功状态的 promise 对象
               .then(res => {
                   console.log('成功')
               }).catch(res => {
                   console.log('失败')
               })
      
    
  • 强行返回一个失败状态
  • Promise.reject()    // 5. 强行帮我们返回一个失败状态的 promise 对象
               .then(res => {
                   console.log('成功')
               }).catch(res => {
                   console.log('失败')
               })
    

数组扁平化

 const arr = [1, 2, 3, [4, 5, [6, 7, [8, 9]]]]
  1. 面试版:

     console.log('原始数据: ', arr)
    ​
            // 面试版写法
            function flat(origin) {
                const newArr = []
    ​
                // 数组扁平化核心函数
                function inner(innerOrigin) {
    ​
                    innerOrigin.forEach(item => {
                        if (Object.prototype.toString.call(item) === '[object Array]') {
                            inner(item)
                        } else {
                            newArr.push(item)
                        }
                    })
    ​
                }
                // 调用核心函数, 并将原始数组传递进去
                inner(origin)
                return newArr
            }
            const newArr = flat(arr)
    
  2. toString----将数组内的所有成员转换为字符串并通过逗号合并在一起----这种方式处理数字或者字符串

     const newArr = arr.toString().split(',')
            console.log(newArr[3] - 0)
            
    
  3. flat( )------数组给我们提供的扁平化的方法-----需要接受一个参数,代表拆几层,默认不传递为1

    Infinity: 在JS中代表正无穷

    -Infinity: 代表负无穷

     const newArr = arr.flat(Infinity)
            console.log('扁平化之后的新数组: ', newArr)
    ​
    
  4. 最后的结果:

     arr === [1,2,3,4,5,6,7,8,9]
    

设计模式

  • 设计模式:为了实现某一类功能的一个简洁优化的写法
  • 单例模式:一个构造函数(类),一生只能有一个实例化对象
  • 需求:一个构造函数,在实例化对象时,判断是否 为第一次实例化
  • ------如果是第一次,创建一个实例化对象,然后返回
  • --------如果不是第一次,想办法拿到第一次的实例化对象,然后返回
  • 解决:拿一个变量,初始值给一个nul
  • l-------在实例化对象时,第一次实例化,直接将实例化赋值给变量,然后将变量返回
  • -------后续再实例化的时候,直接返回刚才的变量
  • class Dialog {
               constructor() {
                   console.log('创建一个 弹出框 插入到 页面中, 类型为: ')
               }
           }
      
           // 单例模式核心代码(有bug)
           let instance = null
           function newDialog() {
               if (instance === null) {
                   instance = new Dialog()
               }
      
               return instance
           }
      
           const n1 = newDialog()
           console.log(n1)
      
           const n2 = newDialog()
           console.log(n2)
      
    
  • 总代码:
  • class Dialog {
              constructor(title) {
                  console.log('创建一个 弹出框 插入到 页面中, 类型为: ')
                  this.title = title
              }
          }
      
          let instance = null
          function newDialog(type) {
      
              if (instance === null) {
                  instance = new Dialog(type)
              }
      
              return instance
          }
    
  • 问题1:全局多了一个变量instance
  • 解决问题1:通过闭包解决
  • class Dialog {
               constructor(title) {
                   console.log('创建一个 弹出框 插入到 页面中, 类型为: ')
                   this.title = title
               }
           }
    

// 1. 通过 闭包, 解决问题1 function fn(type) { let instance = null return function newDialog() {

              if (instance === null) {
                  instance = new Dialog(type)
              }
  
              return instance
          }
      }
​
  
​
* 利用自执行函数优化
​
* ```javascript
   
  const newDialog = (function fn() {
              let instance = null
              return function inner(type) {
  
                  if (instance === null) {
                      instance = new Dialog(type)
                  }
  
                  return instance
              }
          })()
  • 问题2:传递多个参数 无法生效
  • 解决:
  • class Dialog {
               constructor() {
                   console.log('创建一个 弹出框 插入到 页面中, 类型为: ')
                   this.title = ''
               }
               // 每次需要 给 title 赋值, 直接调用这个方法即可
               init (title) {
                   this.title = title
                   console.log('当前 title 的值为: ', title)
               }
           }
           const newDialog = (function fn() {
               let instance = null
               return function inner(type) {
      
                   if (instance === null) {
                       instance = new Dialog()
                   }
      
                   instance.init(type)
      
                   return instance
               }
           })()
    
  • 问题3:构造函数的类和实际使用创建的函数不是一个名
  • 解决:
  • const Dialog = (function fn() {
              let instance = null
      
              class Dialog {
                  constructor() {
                      console.log('创建一个 弹出框 插入到 页面中, 类型为: ')
                      this.title = ''
                  }
                  // 每次需要 给 title 赋值, 直接调用这个方法即可
                  init(title) {
                      this.title = title
                      console.log('当前 title 的值为: ', title)
                  }
              }
      
              return function inner(type) {
                  // 1. 自动帮我们创建一个 对象, 自动帮我们把函数内部的 this 指向这个新建对象
                  // 2. 手动往对象上添加属性
                  // 3. 自动返回一个对象
      
                  // 4. 构造函数内部不要写 return, 返回一个 基本数据类型, 写了和没写一样, 
                  //      如果返回一个 引用数据类型, 写了 构造函数就没用了
      
                  if (instance === null) {
                      instance = new Dialog()
                  }
      
                  instance.init(type)
      
                  return instance
              }
          })()
      
          // 单例模式, 一般不建议写 new
          const n1 = Dialog('警告')
          const n2 = new Dialog('文本')
          const n3 = new Dialog('红色警告')
    
  • 策略模式
  • 核心:减少过多的if...else...
  • 处理:有一个数据结构 内部存储着各种折扣对应的计算总价方式
  • 基础板
  • const price = (function () {
              // 该变量内部 存储 对应的折扣与总价计算方式
              let priceList = {
                  '80%': total => total * 0.8,
                  '70%': total => total * 0.7,
              }
      
              return function inner(type, total) {
                  // console.log('inner 函数开始执行, 计算商品总价')
                  // console.log(type)
                  // console.log(priceList[type])
                  return priceList[type](total)
              }
          })()
      
          // console.log(price)
          let newPrice1 = price('80%', 1000)
          // let newPrice2 = price('70%', 1000)
          console.log(newPrice1)
          // console.log(newPrice2)
    
  • 进阶版------写法1:
  • const price = (function () {
               let priceList = {
                   '80%': total => total * 0.8,
                   '70%': total => total * 0.7,
               }
               // 写法1  必须是 执行了 inner 函数, 才能够给 这个函数上 添加 对应的方法
               return function inner(type, total) {
                   inner.add = (key, value) => {
                       // 这个函数负责 向 priceList 内部 添加 新的 key
                       priceList[key] = value
                   }
                   inner.sub = (key) => {
                       priceList[key] = null
                       // delete priceList[key]
                   }
                   inner.getList = () => {
                       return priceList
                   }
                   return priceList[type](total)
               }
    
  • 进阶版-----写法2:
  • const price = (function () {
                let priceList = {
                    '80%': total => total * 0.8,
                    '70%': total => total * 0.7,
                }
    // 写法2
                function inner(type, total) {
                    return priceList[type](total)
                }
                inner.add = (key, value) => {
                    // 这个函数负责 向 priceList 内部 添加 新的 key
                    priceList[key] = value
                }
                inner.sub = (key) => {
                    priceList[key] = null
                    // delete priceList[key]
                }
                inner.getList = () => {
                    return priceList
                }
    ​
                return inner
            })()
    ​
            let newPrice1 = price('80%', 1000)
            console.log(newPrice1)
    ​
            price.add('60%', total => total * 0.6)
    ​
            price.sub('60%')
    ​
            // let newPrice2 = price('60%', 1000)
            // console.log(newPrice2)
    ​
            let list = price.getList()
            console.log(list)
    ​
            // 所有的引用数据类型(对象 数组 函数), 都可以当作 对象去使用
            // function fn(a, b, c, d) {}
            // // console.dir(fn)
            // fn.abc = 999
            // console.dir(fn)
  • 发布订阅模式

  • 并不是1对1,而是1对多

  • class observer {
              constructor(name) {
                  this.name = name    // 模拟一个店员(不重要)
      
                  // 店员的记录手册
                  this.message = {}
              }
      
              // 原型
              add(type, fn) {
                  if (this.message[type] === undefined) {
                      this.message[type] = []
                  }
      
                  this.message[type].push(fn)
              }
      
              tri(type) {
                  // 调用这个方法, 通知对应的 人员 来购买
                  // console.log(type)
                  // console.log(this.message[type])
                  this.message[type].forEach(item => {
                      // console.log(item)
                      item()
                  })
              }
      
              remove(type, fn) {
                  // console.log(type, fn)
                  // console.log(this.message[type], fn)
                  this.message[type] = this.message[type].filter(item => item !== fn)
              }
          }
      
          const res = new observer('小方')
          console.log('初始数据: ', res)
      
          const fnA = () => {
              console.log('我是张三, 我想购买这本书')
          }
          const fnB = () => {
              console.log('我是李四, 我想购买这本书')
          }
          const fnC = () => {
              console.log('我是王五, 我想购买这本书')
          }
      
          // 新增(留下联系方式)
          res.add('JS从入门到入土', fnA)
          res.add('JS从入门到入土', fnB)
          res.add('颈椎病的预防', fnC)
      
          // 书本到了, 通知对应的预约者, 前来购买
          res.tri('颈椎病的预防')
      
          // 某人, 取消预约一本书
          res.remove('JS从入门到入土', fnA)