zoukankan      html  css  js  c++  java
  • 浅谈vue响应式原理及发布订阅模式和观察者模式

    一.Vue响应式原理

    首先要了解几个概念:

    数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率。

    双向绑定:数据改变,视图改变,数据也随之改变,我们可以使用v-model在表单上创建双向数据绑定。

    数据驱动是Vue最独特的特性之一:开发过程中仅需要关注数据本身,不需要关心数据是如何渲染到视图。

    vue2.X中的响应式原理是基于defineProperty,兼容IE8以上版本,核心原理代码如下:

                  let data={
             msg:'hello',
             count:10
              }
            let vm={}
            proxyData(data)
            function proxyData(data){
                Object.keys(data).forEach(key=>{
                    Object.defineProperty(vm,key,{
                        enumerable:true,
                        configurable:true,
                        writeable:true,
                        //获取值的时候执行
                        get(){
                            console.log('get:',key,data[key])
                            return data[key]
                        },
                        //设置值的时候执行
                        set(newValue){
                            data[key]=newValue
                            console.log('set:',key,newValue)
                            document.querySelector('#app').textContent=data[key]
                        }
                    })
                })
            }
             vm.msg //获取(get方法) hello
             vm.msg='hello World' //设置新属性值并渲染到页面(set方法)
             vm.msg //hello World  

    vue3.X中的响应式原理是基于Proxy,直接监听对象,而非属性,ES6中新增,IE不支持,性能由浏览器优化,性能比defineProperty要好,代码的话相比较defineProperty要简洁一些,对于多个属性的值不需要进行循环遍历处理。

                    let data={
                msg:'hello',
                count:0
            }
            
            //模拟 Vue 实例
            let vm=new Proxy(data,{
                //执行代理行为的函数
                //当访问 vm 的成员会执行
                get(target,key){
                    console.log('get,key:',key,target[key])
                    return target[key]
                },
                set(target,key,newValue){
                    console.log('set,key:',key,newValue)
                    if(target[key] === newValue){
                        return 
                    }
                    target[key]=newValue
                    document.querySelector("#app").textContent=target[key]
                }
            })
            //测试
            vm.msg='Hello World'
            console.log(vm.msg)

    二.发布订阅模式和观察者模式

    1.发布/订阅模式
    这个概念有些抽象,下面举个例子说明下,家长比较关心孩子成绩,天天问孩子成绩出来没,假设可以到孩子所在班级去订阅孩子成绩,一旦考试成绩出来,相当于触发了一个事件,最后有班级的老师以短信的形式通知给家长,

    不需要天天问孩子成绩出来没,家长就是事件的订阅者,老师是事件的发布者,孩子所在的班级可以假想成一个事件的中心。vue中的自定义事件都是基于发布/订阅模式的。下面模拟下发布订阅模式的运行机制:

    //事件触发器
            class EventEmitter(){
                constructor(){
                    // 初始化对象{ 'click':[fn1,fn2],'change':[fn] }
                    this.subs=Object.create(null)
                }
                //注册事件
                $on(eventType,handler){
                    this.subs[eventType] = this.subs[eventType] || []
                    this.subs[eventType].push(handler)
                }
                //触发事件
                $emit(eventType){
                    if(this.subs[eventType]){
                        this.subs[eventType].forEach(handler => {
                            handler()
                        })
                    }
                }
            }
            //测试
            
            let em =new EventEmitter()
            
            em.$on('click',()=>{
                console.log('click1')
            })
            em.$on('click',()=>{
                console.log('click2')
            })
            em.$emit('click') //打印结果 click1,click2

    二.观察者模式

    观察者模式和订阅模式的区别是没有事件中心,只有发布者和订阅者,并且发布者需要知道订阅者的存在.

    概念:

    观察者 --Watcher

    update():当事件发生时,具体要做的事情。

    发布者 --Dep

    subs数组:存储所有的观察者

    addSub():添加观察者

    notify():当事件发生,调用所有观察者的update()方法

    //发布者-目标
            class Dep{
                constructor() {
                    //记录所有的订阅者
                    this.subs=[]
                }
                //添加订阅者
                addsub(sub){
                    if(sub && sub.update){
                        this.subs.push(sub)
                    }
                }
                //发布通知
                notify(){
                    this.subs.forEach(sub=>{
                        sub.update()
                    })
                }
            }
            //订阅者-观察者
            class Watcher{
                update(){
                    console.log('update')
                }
            }
            //测试
            let dep=new Dep()
            let watcher=new Watcher()
            dep.addsub(watcher)
            dep.notify() //打印结果 update

    总结:

    观察者模式是由具体目标调度,比如当事件触发,Dep就会去调用观察者的方法,所以观察者的订阅者和发布者之间是存在依赖的。

    发布订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在。

    ---感谢阅读,o(* ̄︶ ̄*)o开心每一天!
  • 相关阅读:
    How To Scan QRCode For UWP (4)
    How To Crop Bitmap For UWP
    How To Scan QRCode For UWP (3)
    How To Scan QRCode For UWP (2)
    How To Scan QRCode For UWP (1)
    How to change windows applicatioin's position via Win32 API
    8 Ways to Become a Better Coder
    How to resize or create a thumbnail image from file stream on UWP
    C# winform压缩文件夹带进度条
    MS ACCESS MID函数
  • 原文地址:https://www.cnblogs.com/websiteblogs/p/15115681.html
Copyright © 2011-2022 走看看