美文网首页
前端零碎知识点---有点乱

前端零碎知识点---有点乱

作者: noyanse | 来源:发表于2019-07-29 15:31 被阅读0次
    
    
    /**
     * @description 将数组平铺到指定的深度
     */
    const flatten = (arr, depth = 1) => 
        depth != 1 ? arr.reduce((a, v) => a.concat( Array.isArray(v) ? flatten(v, depth - 1) : v), [])
        : arr.reduce((a, v) => a.concat(v), [])
    
    var flat = (arr) => {
        return arr.flat(Infinity)
    }
     /**
      * 递归 flat
      */
     const flat = (arr) => {
        let result = []
        function each(arr) {
            arr.forEach(item => {
                if (item instanceof Array) {
                    each(item)
                } else {
                    result.push(item)
                }
            })
        }
        each(arr)
        return result.join(',')
    }
     /**
      * 做隐式类型转换 flat
      */
    
     /**
      * 原理:数组 + 加号是双目运算符,
      * arr是数组,不是基本类型也不是数字,是一个对象,
      * 调对象的时候,会调arr的valueof,
      * 如果valueof返回的还不是基本类型,会调toString方法
      * 数组的vauleOf返回的就是数组本身,所以会调toString方法
      * 如果toString方法返回基本类型,到此为止,否则就会报错
      * 
      */
     const flatten = function (arr) {
        let toString = Array.prototype.toString
        Array.prototype.toString = function() {
            return this.join(',')
        }
        let result = arr + ''
        Array.prototype.toString = toString
        return result
     }
     // 所以 改valueOf 也是可以的
     const flatten = function (arr) {
        let value = Array.prototype.valueOf
        Array.prototype.valueOf = function() {
            return this.join(',')
        }
        let result = arr + ''
        Array.prototype.valueOf = value
        return result
     }
     /**
      * es6中的遍历器iterator是对自定义的复杂数据结构,提供遍历的方法
      * 如果想给这个数据结构增加一个遍历器,必须
      * 1. Symbol.iterator为key 
      * 2. value为 function 
      * 3. function 要求必须返回一个对象
      * 4. 这个对象中必须有next方法
      * 
      */
    Array.prototype[Symbol.iterator] = function() {
        let arr = [].concat(this) // [1, [2, [3, [4, 5], 6], 7], 8] 每一次都会调一次next方法
        let getFirst = function(array) {
            let first = array.shift()
            return first
        }
        return {
            next: function() {
                let item = getFirst(arr) // 1, 第二个[2, [3, [4, 5], 6]
                if (item) { // 1 是真,标识下面还有值
                    return {
                        value: item, // 遍历时,当前要返回的值, 当第二次是一个数组的时候,这里有一个隐式类型转换,转成toString了 "2,3,4,5,6"
                        done: false // 是不是已经遍历结束
                    }
                } else {
                    return {
                        done: true
                    }
                }
            }
        }
    }
    var flat = function(arr) {
        let r = []
        for (let i of arr) {
            r.push(i)
        }
        return r.join(',')
    }
    // flat([1, [2, [3, [4, 5], 6], 7], 8]); 
    
    /**
     * @description 使用reduce取代map和filter 更新数组每一项,并筛选部分
     */
    const filterSomeValue = arr => arr.reduce((a, v) => {
        v = v * 2
        if (v > 50) {
            a.push(v)
        }
        return a
    }, [])
    
    /**
     * @description 取整 | 0
     */
    const getInt = num => num | 0
    
    /**
     * @description 单例模式 IIFE方式加闭包 本质是通过函数作用域的方式来隐藏内部作用域的变量
     */
    const Singleton = (function() {
        let _instance = null // 存储单例
    
        const Singleton = function() {
            if (_instance) return _instance // 判断是否已经有单例
            _instance = this
            this.init() // 初始化
            return _instance
        }
    
        Singleton.prototype.init = function() {
            this.foo = 'Singeton Pattern'
        }
    
        Singleton.getInstance = function() {
            if (_instance) return _instance
            _instance = new Singleton()
            return _instance
        }
        
        return Singleton
    })()
    
    const vistor1 = new Singleton()
    const vistor2 = new Singleton()
    const vistor3 = new Singleton.getInstance()
    console.log(vistor1 === vistor3) // true
    
    /**
     * @description 单例模式 ES6的块级作用域 目的是为了 _instance隐藏内部变量
     */
    let getInstance
    
    {
        let _instance = null
    
        const Singleton = function() {
            if (_instance) return _instance // 判断是否已经有单例
            _instance = this
            this.init() // 初始化
            return _instance
        }
    
        Singleton.prototype.init = function() {
            this.foo = 'Singeton Pattern'
        }
    
        getInstance = function() {
            if (_instance) return _instance
            _instance = new Singleton()
            return _instance
        }
    }
    
    const vistor1 = getInstance()
    const vistor2 = getInstance()
    
    /**
     * @description 单例 抽离 创建 和 功能逻辑
     */
    class FuncClass {
        constructor(bar) {
            this.bar = bar
            this.init()
        }
        init() {
            this.foo = 'Single Pattern'
        }
    }
    
    const Singleton = (function() {
        let _instance = null
    
        const ProxySingleton = function(bar) {
            if (_instance) return _instance
            _instance = new FuncClass(bar)
            return _instance
        }
        ProxySingleton.getInstance = function(bar) {
            if (_instance) return _instance
            _instance = new Singleton(bar)
            return _instance
        }
        return ProxySingleton
    })()
    
    const vistor1 = new Singleton('单例1')
    const vistor2 = new Singleton('单例2')
    const vistor3 = Singleton.getInstance()
    
    /**
     * @description 单例模式的应用 element-ui 的 loading
     */
    

    import Vue from 'vue'
    import loadingVue from './loading.vue // 自己写的Loading组件

    const LoadingConstructor = Vue.extend(loadingVue)
    
    let fullscreenLoading
    
    const Loading = (options = {}) => {
        if (options.fullscreen && fullscreenLoading) { // 如果之前创建国,直接返回
            return fullscreenLoading
        }
    
        let _instance = new LoadingConstructor({
            el: document.createElement('div'),
            data: options
        })
    
        if (options.fullscreen) {
            fullscreenLoading = _instance
        }
        
        return _instance
    }
    
    export default Loading
    
    /**
     * 设计模式-工厂函数 根据不同的输入返回不同类的实例 主要思想是对象的创建和实现分离
     */
    class Restaurant {
        static getMenu(menu) {
            switch (menu) {
                case '鱼香肉丝':
                    return new YuXiangRouSi()
                case '宫保鸡丁':
                    return new GongBaoJiDin()
                default:
                    throw new Error('本店没有')
            }
        }
    }
    
    class YuXiangRouSi {
        constructor () {
            this.type = '鱼香肉丝'
        }
        eat() {
            console.log(this.type + '好吃~')
        }
    }
    
    class GongBaoJiDin {
        constructor () {
            this.type = '宫保鸡丁'
        }
        eat() {
            console.log(this.type + '好吃~')
        }
    }
    
    const dish1 = Restaurant.getMenu('鱼香肉丝')
    const dish2 = Restaurant.getMenu('宫保鸡丁')
    
    /**
     * @description Vue 源码中的工厂模式 虚拟DOM树机制 createElement生成VNode 用来映射真是DOM节点
     */
    createElement('h3', { class: 'main-title' }, [
        createElement('img', { class: 'avatar', attrs: { src: './avatar.png' } }),
        createElement('p', { class: 'user-desc' }, '我要的飞翔,不是谁的肩膀')
    ])
    
    // createElement:
    class Vnode(tag, data. children) {
        // ...
    }
    function createElement(tag, data, children) {
        return new Vnode(tag, data, children)
    }
    
    /**
     * @description 抽象工厂模式
     */
    // 饭店方法
     class Restaurant {
        static orderDish(type) {
            switch (type) {
                case '鱼香肉丝':
                    return new YuXiangRouSi()
                case '宫保鸡丁':
                    return new GongBaoJiDin()
                default:
                    throw new Error('本店没有~')
            }
        }
     }
    // 菜品抽象类
     class Dish { // 父类
         constructor() {
             if (new.target === Dish) {
                 throw new Error('抽象类不能直接实例化')
             }
             this.kind = '菜'
         }
         // 抽象方法 相当于定义一个接口,由子类继承
         eat() {
             throw new Error('抽象方法不能被调用')
         }
     }
    
     // 菜品 继承菜品抽象类
     class YuXiangRouSi extends Dish {
         constructor() {
             super()
             this.type = '鱼香肉丝'
         }
    
         eat() {
             console.log(this.kind, this.type, '鱼香肉丝')
         }
     }
    
     class GongBaoJiDin extends Dish {
        constructor() {
            super()
            this.type = '宫保鸡丁'
        }
    
        eat() {
            console.log(this.kind, this.type, '宫保鸡丁')
        }
     }
    
     const dish0 = new Dish() // Error 抽象类不能直接实例化
     const dish1 = Restaurant.orderDish('鱼香肉丝')
     dish1.eat()
    
    
     /**
      * 林衣踩在一个板凳上,左手拿着颜料,右手拿着画笔,给自己的家门口写上四个大字,艺术设计
      * 结束之后,满意的看着自己的作品,含笑打开房门,看着自己屋里的格局,左边窗户上挂着一把她从上个世纪
      * 拿回来的剑,
      * 小黄此时在她脚底下转圈,她把目光放到桌上的一个工厂模型,这是她准备去的地方,那里有她这个时代要找的人,
      * 传说中可以拯救末世的人。
      * 
      *
      */
     /**
      * @description 建造者模式 分布构建一个复杂对象,并允许韩兆步骤构造
      * 如: 汽车, 笔记本, 很多部件都由零件制造商制造 指挥长决定如何组装
      */
     
     
    /**
     * @description 代理模式,又称为委托模式,他为目标对象创造了一个代理对象,以控制对目标对象的访问
     * Visitor -----------> Proxy --------------> Target
     * Visitor <----------- Proxy <-------------- Target
     * 如 axios 拦截器, 代理模式和装饰者模式很像,但是代理模式是会对目标对象的访问进行控制,axios拦截器可以取消
     * 请求,而装饰者模式是在目标对象上添加新的功能
     * 
     * vue2.x 通过劫持各个属性的 getter 和 setter ,在数据变化时,通过发布订阅模式发布消息给订阅者
     * 触发相应的监听回调,实现数据响应式
     * vu2.x 的缺点: 
     * 1. 无法监听利用索引直接设置数组的项
     * 2. 无法监听数组的长度变化
     * 3. 无法监听ES6的 Set, WeakSet, Map, WeakMap 的变化
     * 4. 无法监听Class 类型的数据
     * 5. 无法监听对象属性的新增或者删除
     */
    
    //  const proxy = new Proxy(target, handler)
    const SuperStar = {
        name: '小鲜肉',
        scheduleFlag: false, // 档期标识 默认没空
        playAdvertisement(ad) {
            console.log(ad)
        }
    }
    
    const ProxyAssistant = {
        name: '经纪人张某',
        scheduleTime(ad) {
            const schedule = new Proxy(SuperStar, {
                set(obj, prop, val) {
                    if (prop !== prop.scheduleFlag) return
                    if (!obj.scheduleFlag && val) {
                        obj.scheduleFlag = true
                        obj.playAdvertisement(ad) // 安排
                    }
                }
            })
    
            setTimeout(() => {
                console.log('小鲜鲜有空了')
                schedule.scheduleFlag = true
            }, 2000)
        },
    
        playAdvertisement(reward, ad) {
            if (reward > 1000000) {
                console.log('没问题,我们小鲜鲜最喜欢拍广告了')
                ProxyAssistant.scheduleTime(ad)
            } else {
                console.log('没空,滚')
            }
        }
    }
    
    ProxyAssistant.playAdvertisement(10000, '广告')
    
    /**
     * @description 享元模式 公用某些资源
     */
    let examCardNum = 0 // 驾考车总数
    
    class ExamCar {
        constructor(carType) {
            examCardNum++
            this.cardId = examCardNum
            this.carType = carType ? '手动挡' : '自动挡'
            this.usingState = false // 是否正在占用
        }
    
        // 在本车上考试
        examine(candidateId) {
            return new Promise(resolve => {
                this.usingState = true
                console.log(`考生 ${candidateId} 在 ${this.carType}驾考车-${this.cardId}上考试`)
                setTimeout(() => { // 0 - 2s 考完后
                    this.usingState = false
                    resolve()
                }, Math.random() * 2000)
            })
        }
    }
    
    // 手动挡汽车对象池
    ManualExamCarPool = {
        _pool: [], // 驾考车对象池
        _candidateQueue: [], // 考生队列
    
        // 注册考生 ID 列表
        registCandidates(candidateList) {
            candidateList.forEach(candidateId => this.registCandidate(candidateId))
        },
    
        // 注册手动挡考生
        registCandidate(candidateId) {
            const examCar = this.getManualExamCar() // 找一个未被占用的手动挡驾考车
            if (examCar) {
                examCar.examine(candidateId) // 开始考试, 考完了让队列中的下一个考生开始考试
                    .then(() => {
                        const nextCandidateId = this._candidateQueue.length && this._candidateQueue.shift()
                        nextCandidateId && this.registCandidate(nextCandidateId)
                    })
            } else { // 如果没有空车,将考生推入队列
                this._candidateQueue.push(candidateId)
            }
        },
    
        // 注册手动挡车
        initManualExamCar(manualExamCarNum) {
            for(let i = 0; i <= manualExamCarNum; i++) {
                this._pool.push(new ExamCar(true))
            }
        },
    
        // 获取状态为未被占用的手动挡车
        getManualExamCar() {
            return this._pool.find(car => !car.usingState)
        }
    }
    
    ManualExamCarPool.initManualExamCar(3) // 一共三辆考车
    ManualExamCarPool.registCandidates([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) // 10个考生来考试
    
    // 数据库连接池
    const mysql = require('mysql')
    
    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '123456',
        database: 'mydb',
        port: '3306'
    })
    
    // 连接回调,在回调中增删改查
    connection.connect()
    
    // 关闭连接
    connection.end()
    
    // 连接池的创建
    const pool = mysql.createPool({
        host: 'localhost',
        user: 'root',
        password: '123456',
        database: 'mydb',
        port: '3306'
    })
    
    pool.getConnection((err, connection) => {
        // 数据库操作
        connection.release() // 将连接释放回连接池中
    })
    
    // 关闭连接池
    pool.end()
    
    /**
     * @description REST 以及 6个限制
     * REST是一种风格,万维网网络架构风格 Representational State Transfer
     * Representational 表示,数据的表现形式 如json xml
     * State 状态 当前的状态 可变的状态
     * Transfer 传输 数据在互联网上传输
     * 
     * 6 个限制
     * 1. 客户端--服务器(Client-Server) CS架构
     * 服务端专注数据存储,提升简单性 ---形容词来自于REST作者的博士论文
     * 前段转出用户界面,提升可移植性
     * 2. 无状态
     * 所有的用户会话信息都保存在客户端
     * 每次请求必须包含所有信息,不能依赖上下文信息
     * 服务端不用保存会话信息,提升了简单性,可靠性,可见性(每次请求要包含很多信息)
     * 3. 缓存(Cache)
     * 所有服务端响应都要被表位可缓存或不可缓存
     * 如 静态资源,至少在一个版本内不会变
     * 减少交互,提升速度
     * 4. 统一接口 (Uniform Interface)
     * 接口与实现解耦,前后端可以独立开发迭代
     * 5. 分层系统(Layered System)
     * 每层只知道相邻的一层,后面隐藏的就不知道了
     * 客户端不知道是和代理还是很真实服务器通信
     * 中间件,不用关心业务逻辑,只要做系统中的分层
     * 其它层:安全层, 负载均衡(分发流量),缓存层
     * 6. 按需代码(code on Demand 可选)
     * 客户端可以下载运行服务端传来的代码(如, js)
     * eval() 可以执行
     * 简化客户端
     * 
     * 
     * 统一接口 的限制:
     * 1. 资源的标识
     * 资源是任何可以命名的事物,如,用户,评论
     * 每个资源可以通过URI被唯一标识 URI 是统一资源标识符,URI最常见的形式是统一资源定位符,URL
     * 2. 通过表述来操作资源
     * 表述 如 JSON XML 传给服务端,服务端来操作
     * 3. 自描述信息
     * 媒体类型(application/json)
     * HTTP方法
     * 是否缓存 Cache-Control
     * 
     * 
     * 控制器的本质是中间件,中间件的本质是函数
     * 
     * koa 断点调试
     * 在vscode中在要调试的文件界面按下F5就启动了
     * 
     * 错误处理
     * 1. 运行时错误,语法没有错误的前提下,返回500 
     * 2. 逻辑错误,找不到404 
     * 先决条件失败402 (请求某个ID不存在)
     * 无法处理的实体 422 (参数格式不对)
     * 4开头的大多是逻辑错误
     * 
     * 防止程序挂掉,try catch
     * 告诉用户错误信息
     * 便于开发调试
     * 
     * koa自带的错误处理
     * koa找不到的情况下默认返回404
     * 
     * 
     */
    // 123456789876543212345678987654321
    const getNum = n => {
        let num = 0
        let flag = true
        for(let i = 0; i <= n; i++) {
            if (num == 1) flag = true
            if (num == 9) flag = false
            flag ? num++ : num--
        }
        return num
    }
    
    // promise 用法
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('fullfilled')
        }, 1000)
    })
    
    /**
     * 构造函数,必须接受一个函数作为参数,函数又接收 resolve, reject 两个参数,也是函数
     * 1. 必须是函数
     * 2. 状态值
     * promise 对象存在三种状态
     * - Pending 进行中
     * - Fullfilled 已成功
     * - Rejected 已失败
     * 状态只能由 Pending 变为Fullfilled 或者 Pending 变为 Rejected
     * 且状态改变之后不会发生变化,会一直保存这个状态
     * Promise 的值是指状态改变时,传给回调函数的值
     */
    
     // 判断变量是否为函数
     const isFunction = val => typeof(val) === 'function'
    
    // 定义三个常量 标记Promise对象的三种状态和值
    const PENDING = 'PENDING'
    const FULLFILLED = 'FULLFILLED'
    const REJECTED = 'REJECTED'
    
    // 定义我们自己的 promise
    class MyPromise {
        constructor(exector) {
            if (!isFunction(exector)) {
                throw new Error('MyPromise must accept a function as a parameter')
            }
            
            // 添加状态
            this._status = PENDING
            this._value = undefined
            // 添加成功回调函数队列
            this._fullfilledQueues = []
            // 添加失败回调函数队列
            this._rejectedQueues = []
    
            try {
                exector(this._resolve.bind(this), this._reject.bind(this))
            } catch (err) {
                this._reject(err)
            }
        }
        // 添加resolve时执行的函数
        _resolve(val) {
            if (this._status !== PENDING) return
            // 依次执行成功队列中的函数
            const run = () => {
                this._status = FULLFILLED
                this._value = val
                this._fullfilledQueues.map(cb => cb())
            }
            // 为了支持同步的Promise 这里采用异步调用
            setTimeout(() => run(), 0)
        }
        // 添加reject时执行的函数
        _reject(err) {
            if (this._status !== PENDING) return
            const run = () => {
                this._status = REJECTED
                this._value = err
                let cb
                while (cb = this._rejectedQueues.shift()) {
                    cb(err)
                }
            }
            setTimeout(run, 0)
        }
    
        // 添加 then 方法
        then(onFullfilled, onRejected) {
            const { _value, _status } = this
            // 返回一个新的 Promise
            return MyPromise((onFullfilledNext, onRejectedNext) => {
                // 封装一个成功时执行的函数
                let fullfilled = value => {
                    try {
                        if (!isFunction(onFullfilled)) {
                            onFullfilledNext(value)
                        } else {
                            let res = onFullfilled(value)
                            if (res instanceof MyPromise) {
                                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后再执行
                                res.then(onFullfilledNext, onRejectedNext)
                            } else {
                                // 否则将返回的结果作为参数,传入下一个then回调,并立即执行下一个then
                                onFullfilledNext(res)
                            }
                        }
                    } catch (err) {
                        // 如果函数执行出错,新的promise对象状态为失败
                        onRejectedNext(err)
                    }
                }
    
                // 封装一个失败时执行的函数
                let rejected = error => {
                    try {
                        if (!isFunction(onRejected)) {
                            onRejectedNext(error)
                        } else {
                            let res = onRejected(error)
                            if (res instanceof MyPromise) {
                                res.then(onFullfilledNext, onRejectedNext)
                            } else {
                                onFullfilledNext(res)
                            }
                        }
                    } catch (err) {
                        onRejectedNext(err)
                    }
                }
                switch (_status) {
                    // 当状态为 pending 时,将then 方法回调函数计入执行队列等待
                    case PENDING:
                        this._fullfilledQueues.push(onFullfilled)
                        this._rejectedQueues.push(onRejected)
                        break
                    // 当状态已经改变时,立即执行对象的回调
                    case FULLFILLED:
                        fullfilled(_value)
                        break
                    case REJECTED:
                        rejected(_value)
                        break
                }
    
            })
        }
    }
    
    // promise 的 then 方法接收两个参数 参数可选
    // promise.then(onFullfilled, onRejected)
    /**
     * 多次调用then 
     * then 可以被同一个Promise对象调用多次
     * 当promise成功状态时,所有onFullFilled需要按注册顺序依次回调
     * 失败同上
     * then方法必须返回一个新的promise对象
     * promise支持链式调用
     */
    
    let promise1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve()
        }, 1000)
    })
    
    promise2 = promise1.then(res => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('return promise')
            }, 2000)
        })
    })
    promise2.then(res => {
        console.log(res)
    })
    
    
    /**
     * @description 适配器 
     */
    var chinaPlug = {
        type: '中国插头',
        chinaInPlug() {
            console.log('开始充电')
        }
    }
    chinaPlug.chinaInPlug() // 开始供电
    
    // 当我们到日本了,要用日本的适配
    var japanPlug = {
        type: '日本插头',
        japanInPlug() {
            console.log('开始供电')
        }
    }
    
    // 日本插头电源适配器
    function japanPlugAdapter(plug) {
        return {
            chinaInPlug() {
                return plug.japanInPlug()
            }
        }
    }
    
    japanPlugAdapter(japanPlug).chinaInPlug() // 开始供电
    
    /**
     * @description 装饰者模式
     */
    var originHouse = {
        getDesc() {
            console.log('毛坯房')
        }
    }
    
    function furniture() {
        console.log('搬入家具')
    }
    function painting() {
        console.log('刷漆')
    }
    
    originHouse.getDesc = function() {
        var getDesc = originHouse.getDesc
        return function() {
            getDesc()
            furniture()
        }
    }
    
    originHouse.getDesc = function() {
        var getDesc = originHouse.getDesc
        return function() {
            getDesc()
            painting()
        }
    }
    
    originHouse.getDesc()
    
    /**
     * @description 外观模式 --- 一个统一的外观为复杂的子系统提供一个简单的高层功能接口
     */
    var uav = {
        // 电子调速器
        diantiao1: {
            up() {
                console.log('电调1发送指令:电机1增大转速')
                uav.dianji1.up()
            },
            down() {
                console.log('电调1发送指令:电机1减少转速')
                uav.dianji1.up()
            }
        },
        diantiao2: {
            up() {
                console.log('电调2发送指令:电机1增大转速')
                uav.dianji1.up()
            },
            down() {
                console.log('电调2发送指令:电机1减少转速')
                uav.dianji1.up()
            }
        }
    }
    // 遥控器
    controller: {
        up() {
            uav.diantiao1.up()
            uav.diantiao2.up()
        }
        down() {
            uav.diantiao1.down()
            uav.diantiao2.down()
        }
        // ...
    }
    
    // 函数参数重载
    function domBinaEvent(nodes, type, selector, fn) {
        if (fn === undefined) {
            fn = selector
            selector = null
        }
        // ...
    }
    domBinaEvent(node, 'click', '#div1', fn)
    domBinaEvent(node, 'click', '#div1')
    
    // vue 中的函数参数重载
    export function createElement(
        context,
        tag,
        data,
        children,
        normalizationType,
        alwaysNormalize
    ) {
        if (Array.isArray(data) || isPrimitive(data)) {
            normalizationType = children
            children = data
            data = undefined
        }
    }
    
    /**
     * @description 发布 订阅 又称观察者模式
     * 比如:群聊,所有群聊的人都订阅了这个群,
     * 当有人发消息时,群会主动通知给所有订阅这个群的人
     * 1. Publisher: 发布者 当消息发生时,负责通知订阅者
     * 2. Subscriber: 订阅者 当消息发生时被通知的对象
     * 3. SubscriberMap: 储存所有订阅者的数组
     * 4. type: 消息类型,订阅者可以订阅不同消息类型
     * 5. subscribe: 将订阅者添加到SubscriberMap中
     * 6. unsubscribe: 将SubscriberMap中删除订阅者
     * 7. notidy: 遍历通知 SubscriberMap 中对象的每个订阅者
     */
    const Publisher = (function() {
        const _subsMap = {} // 储存订阅者
        return {
            // 消息订阅
            subscribe(type, cb) {
                if (_subsMap[type]) {
                    if (!_subsMap[type].includes(cb)) {
                        _subsMap[type].push(cb)
                    }
                } else _subsMap[type] = [cb]
            },
            // 消息退订
            unsubscribe(type, cb) {
                if (!_subsMap[type] || !_subsMap[type].includes(cb)) return
                const idx = _subsMap[type].indexOf(cb)
                _subsMap[type].splice(idx, 1)
            },
            // 消息发布
            notify(type, ...payload) {
                if (!_subsMap[type]) return
                _subsMap[type].forEach(cb => cb(...payload))
            }
        }
    })()
    
    Publisher.subscribe('运动鞋', message => console.log('33码 红色'))
    
    Publisher.notify('运动鞋', '运动鞋到货啦...')
    
    class Publisher {
        constructor() {
            this._subsMap = {}
        }
    
        // 消息订阅
        subscribe(type, cb) {
            if (_subsMap[type]) {
                if (!_subsMap[type].includes(cb)) {
                    _subsMap[type].push(cb)
                }
            } else _subsMap[type] = [cb]
        }
        // 消息退订
        unsubscribe(type, cb) {
            if (!_subsMap[type] || !_subsMap[type].includes(cb)) return
            const idx = _subsMap[type].indexOf(cb)
            _subsMap[type].splice(idx, 1)
        }
        // 消息发布
        notify(type, ...payload) {
            if (!_subsMap[type]) return
            _subsMap[type].forEach(cb => cb(...payload))
        }
    }
    
    const adadis = new Publisher()
    adadis.subscribe('运动鞋', message => console.log('33码 红色'))
    Publadadisisher.notify('运动鞋', '运动鞋到货啦...')
    
    /*
     * 
     */
    
    /**
     * @description 考察点,变量提升
     */
    var a = 10
    function foo () {
        console.log(a)
        var a = 20 // undefined
        // let a = 20 // ReferenceError: a is not defined
    }
    foo() // undefined
    
    /**
     * @description 考察点
     */
    var array = []
    for (var i = 0; i < 3; i++) {
        array.push(() => i)
    }
    var newArray = array.map(el => el())
    console.log(array, newArray)
    
    /**
     * @description 考察点,setTimeout异步,让出当前线程
     */
    function foo() {
        foo(); //执行1000次左右会发生堆栈溢出的错误, 
        //setTimeout(foo, 0); //永远不会堆栈溢出
    }
    foo()
    /**
     * 执行settimeout函数这个时候虽然它又继续调用自己,
     * 但是这里可以理解多线程操作了,
     * 只是开启另一个线程来启动foo,
     * 而当前线程仍然继续执行,
     * 当当前线程的foo执行完成后,
     * 自然就出栈了,每一次的FOO执行都是这个过程,
     * 所以栈里不会容量超标的
    */
    
    function foo(){ // 会造成页面卡死
        return Promise.resolve().then(foo) 
    }
    /**
     * @description 如何让一个对象可迭代
     */
    var obj = { x: 1, y: 2, z: 3 }
    obj[Symbol.iterator] = function() {
        return {
            next: function() {
                if (this._count === 3) {
                    return {
                        value: this._count,
                        done: true
                    }
                }
                this._count += 1
                return {
                    value: this._count,
                    done: false
                }
            },
            _count: 0
        }
    };
    [...obj]
    

    相关文章

      网友评论

          本文标题:前端零碎知识点---有点乱

          本文链接:https://www.haomeiwen.com/subject/yevbrctx.html