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开心每一天!
  • 相关阅读:
    mysql热备脚本
    linux系统编程-进程
    15-模块
    14-面向对象3
    13-面向对象2
    12-面向对象1
    02-对比两个文件的差异
    11-面向对象基础
    08-不定长函数
    07-缺省参数
  • 原文地址:https://www.cnblogs.com/websiteblogs/p/15115681.html
Copyright © 2011-2022 走看看