设计模式(单例模式-策略模式-数组扁平化-图片懒加载)

44 阅读4分钟

单例模式

  • 创建一个类, 这个类的一生只能有一个实例化对象

  • 完成思路:

    • 首先要有一个 class
    • 在每次准备实例化这个 lei 之前, 先判断之前有没有对这个 lei 进行过实例化
      • 如果进行过, 那么我们不在进行新的实例化, 而是拿到之前的 实例化对象
      • 如果没有进行过, 那么我们这时候开始进行一个实例化
 // 单例模式升级
 class Dialog {
            constructor() {
                this.naem = "李四"
            }
        }

        let flag = null

        function fn() {
            if (flag === null) {
                flag = new Dialog()
            }
            return flag
        }

//====================封装以后为下面的代码==============

        const fn = (() => {
            let flag = null
            class Dialog {
                constructor() {
                    this.text = "李四"
                }
                say(text) {
                    this.text = text
                } 
            }
            return function (text) {
                if (flag === null) {
                    flag = new Dialog() 
                }
                flag.say(text) //在这里直接调用实例化对象的方法
                return flag
            }
        })()   

        const d1 = fn("d1的文本")
        console.log(d1);
        const d2 = fn("d2的文本")
        console.log(d1);
        const d3 = fn("d3的文本")
        console.log(d3);
        console.log(d1);

策略模式

  • 只是为了解决代码中 过多的 if...else 嵌套的问题
        // 计算一本书的价格
        // 如果打八折是多少钱
        // 如果打七折是多少钱
        // 如果打六折是多少钱
 const calcPrice = (() => {
            // 1. 先创建一个数据, 存储我们的折扣以及对应的价格
            const priceList = {
                '80%': function (total) {
               
                    // return '0.8 * 总价'
                    return 0.8 * total
                },
                '70%': (total) => {
                    return 0.7 * total
                },
                '60%': total => 0.6 * total 
            }

            // 2.0 返回一个函数, 这个函数能够帮助你计算价格
        
            function inner(total, type) {
                return priceList[type](total)
            }

            // JS 中 所有的 引用数据类型 能够当成 对象使用


            // 2.1 添加折扣功能
            inner.add = function (key, value) {
                priceList[key] = value

            }

            // 2.2 删除折扣功能
            inner.del = function (key) {
                delete priceList[key]
                // console.log(priceList)
            }

            // 2.3 获取所有折扣列表
            inner.get = function () {
                return priceList
            }

            return inner
        })()



        calcPrice.add('300-30', (total) => total - Math.floor(total / 300) * 30)
        calcPrice.del('60%')
        console.log(calcPrice.get())

发布订阅模式

  • 去书店买书
  1. 去书店, 没有
  2. 留下联系方式, 将来书店会根据联系方式, 通知你 书有了
  3. 有了书之后, 去书店
  • 方案1:
  • {
    • 本的名字1: [联系人1, 联系人2, 联系人3, .....]
    • 本的名字2: [联系人1, 联系人2, 联系人3, .....]
  • }
  • 方案2:
  • [
    • {
      • book: 书名1,
      • num: 联系方式1
    • },
    • {
      • book: 书名1,
      • num: 联系方式2
    • },
    • {
      • book: 书名1,
      • num: 联系方式3
    • },
    • {
      • book: 书名2,
      • num: 联系方式4
    • }
  • ]
   class cs {
            constructor() {
                this.name = '张三'  // 售货员的名字, 有没有这个属性 不重要

                this.message = {}   // 按照方案一的思路去存储
            }


            /**
             *  {
             *      书本1: [联系人1, 联系人2, 联系人3, ....]
             *      书本2: [联系人1, 联系人2, 联系人3, ....]
             *  }
            */
           // 给书本加入联系人
            add(bookName, user) {
                // this.message[bookName] = [user]  


                // 调用当前方法, 能够预定一个书本 (只是留下联系方式)
                if (this.message[bookName] === undefined) { this.message[bookName] = [] }

                this.message[bookName].push(user)
            }
           // 给书本加入联系人
            del(bookName, user) {
                // 调用当前方法, 能够取消预订一个书本 (把联系方式 删掉)

                this.message[bookName].forEach((item, index) => {
                    if (item === user) {
                        delete this.message[bookName][index]
                    }
                })

            }

            tz(bookName) {
                this.message[bookName].forEach(item => item())
            }
        }

        const obj = new cs()

        // 创建一些联系人
        const user_1 = () => console.log('我是联系人1, 我来买书来了')
        const user_2 = () => console.log('我是联系人2, 我来买书来了')
        const user_3 = () => console.log('我是联系人3, 我来买书来了')
        const user_4 = () => console.log('我是联系人4, 我来买书来了')

        // 联系人开始预约书本
        obj.add('劳动法', user_1)
        obj.add('劳动法', user_2)
        obj.add('劳动法', user_3)

        obj.add('JS从入门到入土', user_4)


        // 过了很长一段时间, 用户2 已经拿到赔偿了, 不需要看劳动法
        obj.del('劳动法', user_2)


        // 又过了一段时间, 劳动法 这本书到了, 开始通知联系人来买书
        obj.tz('劳动法')


        // 又过了一段时间, JS从入门到入土 这本书到了, 开始通知联系人来买书
        obj.tz('JS从入门到入土')

数组扁平化

 const data = [undefined, { name: 'QF001' }, 1, 2, 3, [4, 5, 6, [7, 8, 9]]]
        // console.log(data)
        // console.log([1, 2, 3, 4, 5, 6, 7, 8, 9])


        /**
         *  当前函数能够帮助我们完成数组的扁平化
        */
        function flat(arr) {
            // 1. 创建一个数组, 存储扁平化后的内容
            const target = []

            // 2. 核心代码: 完成扁平化
            function setArr(origin) {

                origin.forEach(item => {
                    if (Object.prototype.toString.call(item) !== '[object Array]') {
                        target.push(item)
                    } else {
                        // 当前分支只要执行, item 的值 一定是一个数组
                        setArr(item)
                    }
                })

            }
            setArr(arr)

            // 3. 将处理好的数据返回
            return target
        }

        const res = flat(data)
        console.log(res)

图片懒加载

  • 在 图片 展示出来前, 我们不渲染图片
  • 等到图片到达(快到达) 可视区域窗口的时候, 我们在渲染图片
const imgEl = document.querySelector('img')

        window.onscroll = function () {
            // console.log('开始判断')
            if (imgEl.src !== '') return

            // 屏幕的高度 + 页面卷去的高度 > 图片的顶部偏移量
            const h = window.innerHeight
            const pageH = document.documentElement.scrollTop
            const top = imgEl.offsetTop

            // - 200 是为了留出一点让网络请求图片的时间, 其实当前案例中 加不加 无所谓
            if (h + pageH > top - 200) {
                console.log('渲染图片')
                imgEl.src = imgEl.dataset.src
            }
        }