精华内容
下载资源
问答
  • Buck变换器是电力电子当中最为重要的一种转换器,由于其在同步斩波模式下与Boost变换器对偶,能实现功率的双向流动控制,因此在电能转换的领域广泛应用。状态反馈与传统的输出反馈(PI控制或PID控制),前者能够直接...
  • 电路配置,电路拓扑系列,降压模式有源钳位电路以及具有高频(HF)链接的双向双向降压-升压dc-dc斩波模式逆变器的瞬时输出电压反馈控制策略分别为提出并在本文中进行了充分研究。 给出了关键电路参数的稳态原理特性...
  • 它借鉴了桌面应用程序MVC的设计思想,Model与View之间通过ViewMode关联,ViewModel负责将Model数据的变化显示到View上,通过将View的改变反馈到Model上这就是我们常说的双向绑定数据机制。 那如何设计MVVM模型模型呢...

    一、设计思路

    MVVM框架相对传统的dom操作模式,最大的优点就是数据的双向绑定。它借鉴了桌面应用程序MVC的设计思想,Model与View之间通过ViewMode关联,ViewModel负责将Model数据的变化显示到View上,通过将View的改变反馈到Model上这就是我们常说的双向绑定数据机制。

    那如何设计MVVM模型模型呢。需要解决两个关键问题:

    • 1、如何知道数据更新。

    • 2、数据更新后,如何通知变化。

    下面我们就分别介绍下vue是如何实现的,理解了这两点,基本上也就明白了双向绑定的机制。

    二、数据劫持

    在ES5中有Object.defineProperty()方法,它能监听各个属性的set和get方法。

     let data ={name:'tcy'}
      Object.defineProperty(data,'name',{
      	set: function(newValue) {
            console.log('更新了data的name:' + newValue);
        },
        get: function() {
            console.log('获取data数据name');
        }
      })
    data.name="fyn";//更新了data的name:fyn
    data.name;//获取data数据name
    
    • Object.defineProperty()方法,有三个参数,分别为待监听的数据对象,待监听的属性,以及对set,get的监听方法。

    • 上例中,对data对象的name属性进行监听,当执行"data.name=‘fyn’"触发set方法,执行"data.name"触发get方法。

    • vue正是采用了该方法,对data的属性进行劫持。我们来模拟实现其劫持的过程。

    //模拟vue的data数据
    // var vm = new Vue(
    // {
    //   data:{
    //       name:'tcy',
    //       age:'20'
    //   }
    // }
    // 	)
    let data ={name:'tcy',age:'20'}
    function observe(data){
    	//获取所有的data数据对象中的所有属性进行遍历
        const keys = Object.keys(data)
        for (let i = 0; i < keys.length; i++) {
        	let val = data[keys[i]];
           defineReactive(data, keys[i],val)//为每个属性增加监听
        }
    }
    function defineReactive(obj,key,val){
       Object.defineProperty(obj, key, {
        enumerable: true,//可枚举
        configurable: true,//可配置
        get: function reactiveGetter () {
          //模拟get劫持
          console.log("get劫持");
          return val;
        },
        set: function reactiveSetter (newVal) {
           	//模拟set劫持
         console.log("set劫持,新值:"+newVal);
         val = newVal;
        }
      })
    }
    observe(data);
    data.name="fyn";//set劫持,新值:fyn
    console.log(data.name);//get劫持,fyn
    
    • data模拟vue.data对象,observer中对data的属性进行遍历,调用defineReactive对每个属性的get和set方法进行劫持。

    • 由此,data数据的任何属性值变化,都可以监听和劫持,上述的第一个问题就解决了。

    • 那view端的数据变化是如何知道的呢,view端改变数据的组件无外乎input,select等,可以用组件的onchange事件监听,这里就不再重点描述。

    • 接下来就要解决第二个问题,监听到数据变化后如何通知。

    三、发布与订阅

    vue在双向绑定的设计中,采用的是观察-订阅模式,前面所讲的数据劫持,其实就是为属性创建了一个观察者对象,监听数据的变化。接下来就是创建发布类和订阅类,如下:

    image

    • observer,创建数据监听,并为每个属性建立一个发布类。

    • Dep是发布类,维护与该属性相关的订阅实例,当数据发生更新时,会通知所有的订阅实例。

    • Watcher是订阅类,注册到所有相关属性的Dep发布类中,接受发布类的数据变更通知,通过回调,实现视图的更新。

    下面我们就模式发布和订阅的过程。

    //对象数据
    let data ={name:'tcy',age:'20',sex:'male'};
    //发布器的uid
    let uid=0;
    //发布器
    class Dep{
       constructor () {
          this.id = uid++//发布器的标识,每次加1
          this.subs = []//订阅者集合
        }
        //添加订阅者实例对象
        addSub(watcher){
          this.subs.push(watcher);
        }
        //移除订阅者实例对象
        removeSub (watcher) {
          remove(this.subs, watcher)
        }
        // 依赖收集函数,在 getter 中执行,在 Dep.target 上找到当前 watcher,并添加依赖
       depend() { 
           Dep.target && Dep.target.addDep(this)
        }
        //通知所有订阅者
        notify () {
        	const subs = this.subs.slice()
        	for (let i = 0, l = subs.length; i < l; i++) {
            subs[i].update();//更新
        }
    }
    }
    //记录当前的watcher实例
    Dep.target = null;
    const targetStack = []
    function pushTarget (_target) {
       if (Dep.target) targetStack.push(Dep.target)
    	Dep.target = _target
    }
    function popTarget () {
      Dep.target = targetStack.pop()
    }
     
    //订阅者
    class Watcher{
       constructor (
        vm,//vm数据对象
        expOrFn,//待监听的属性表达式
        cb//监听到变化后的回调函数
        ){
    	this.vm=vm;
    	this.expOrFn = expOrFn;
    	this.cb = cb;
    	this.value= this.get();
        }
       //添加自身订阅者到发布器
       addDep (dep) {
       	dep.addSub(this)
       }
      //通知更新
      update(){
        this.run();
      }
      //实现视图的更新
      run(){
         let oldValue = this.value//更新前数据
         let value =  this.get();//获取最新值
         if(value != oldValue){
          this.cb.call(this.vm);
      }
    }
      //获取value值,并进行依赖收集
       get(){
         //将自身watcher订阅实例设置给Dep.target
         pushTarget(this);
         //这一步很重要,获取属性值,同时将订阅者实例添加到发布器中
          let value = this.expOrFn.call(this.vm);
          //将订阅实例从target栈中取出并设置给Dep.target
          popTarget();
          return value;
      }
    }
     
    function observer(data){
    	//获取所有的属性进行遍历
    	const keys = Object.keys(data)
    	for (let i = 0; i < keys.length; i++) {
    		let val = data[keys[i]];
           defineReactive(data, keys[i],val)//增加监听
       }
    }
     
     
    function defineReactive(obj,key,val){
        //为每个键都创建一个 dep
        let dep = new Dep();
        Object.defineProperty(obj, key, {
        enumerable: true,//可枚举
        configurable: true,//可配置
        get: function reactiveGetter () {
          if (Dep.target) {
          	dep.depend();
          }
          return val;
      },
      set: function reactiveSetter (newVal) {
           	val = newVal;
          dep.notify(); // 通知所有订阅者
      }
    })
    }
     
     
    //第一步,为每个属性创建一个发布器,并设置set,get劫持
    observer(data);
     
    //第二步,创建监听并实现依赖收集
    var watcher = new Watcher(data,() => {
      "name"+data.name + "age"+data.age
    },() => {
      console.log("实现视图更新");
    });
     
    //第三步,数据变化,触发视图更新
    data.name="fyn";//实现视图更新
    data.sex="female";
    

    下面简单介绍下这几个类

    • 1、发布器Dep类

    构造函数中定义了subs集合,保存所有注册的订阅者实例,uid为发布器对象的标识。
    addSub,removeSub方法,添加和移除的订阅者,维护实例集合。
    depend方法,将当前的watcher实例对象添加到subs集合中。这是会涉及到依赖收集,后面会讲到。
    notify方法,遍历subs中所有维护的订阅者实例,并进行更新操作。

    • 2、订阅者Watcher类,

      • 在构造函数的入参中设置
      • vm-组件对象,即本例的data
      • expOrFn–属性或者表达式
      • cb–更新视图的回调函数

    在实例化的时候,调用get方法,获取当前的监听属性的值,同时触发该属性的get方法(参见defineReactive的get方法),调用dep.depend()将订阅实例添加上发布器Dep中(记住,这步很重要)
    run方法,收到变化通知,比较数据的前后值,调用cb实现视图的更新。

    • 3、defineReactive方法

    该方法与前面的比较,总体框架是一致的,但增加了一些代码。
    let dep = new Dep();
    为数据对象中的每个属性建立一个发布器。
    在get发方法中,将订阅者加入到该属性的发布器subs中
    在set中,数据发生变化,调用dep.notify()通知所有的订阅者,最终执行run方法,比较value值是否发生了变化,如果是,则调用cb的回调方法进行视图更新。


    如果上面的分析没看明白,没关系,我们用具体的实例,分析下其调用过程。

    • 1、为每个属性创建一个发布器,并设置set,get劫持

      执行observer(data);

    • 2、第二步,创建监听,并实现依赖收集

      我们考虑下,模板上有一段代码,“

      name:{{data.name}},age:{{data.age}}”,暂不考虑编译过程,翻译过来,

      "name"+data.name + "age"+data.age
      

    需要对这个表达式进行监听,我们期望name,age的属性发生任何变化,立即通知模板实现页面的刷新,因为data中还有个sex的属性,这个表达式没有涉及到,所以为了提高效率,这个属性的任何变化,无需实现监,这就是依赖收集的概念。

    我们看下是如何做到的。

    在创建这个实例的过程中,会调用get方法,执行下面一段代码:

    let value = this.expOrFn.call(this.vm);
    

    它会触发name,age属性的get劫持方法,调用dep.depend方法,将该监听加入到对应属性的dep对象中。

    • 3、数据变化,触发视图更新

      • 当执行data.name="fyn"时,会被name属性的set方法劫持,调用dep.notify(),该属性的dep对象的subs是有watcher实例的,故执行该watcher实例的updata方法,实现视图更新。

      • 当执行data.sex="female"时,会被sex属性的set方法劫持,调用dep.notify(),但该属性的dep对象的subs是空值,不会有任何更新。

    整个流程的方法调用示意图:
    image

    四、总结


    原文链接:https://blog.csdn.net/tcy83/article/details/80959725

    1.扩展:

    VUE实现双向数据绑定的原理就是利用了 Object.defineProperty()
    这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。它接收三个参数,要操作的对象,要定义或修改的对象属性名,属性描述符。重点就是最后的属性描述符。属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合两种描述符的属性同时使用。上面说的get和set就是属于存取描述符对象的属性。在面试中如何应对?

    2.VUE双向绑定的原理?

    答:VUE实现双向数据绑定的原理就是利用了 Object.defineProperty()
    这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。 代码演示:

    • defineProperty的用法
    var obj = { };var name;
    //第一个参数:定义属性的对象。//第二个参数:要定义或修改的属性的名称。//第三个参数:将被定义或修改的属性描述符。
    Object.defineProperty(obj, "data", {
    //获取值get: 
        function () {return name;},
    //设置值set: 
        function (val) {name = val;console.log(val)}})//赋值调用setobj.data = 'aaa';
        //取值调用getconsole.log(obj.data);
    

    代码演示:defineProperty的双向绑定

    var obj={};
    Object.defineProperty(obj, 'val',{
        set:function (newVal) {
            document.getElementById("a").value =newVal==undefined?'':newVal;
            document.getElementById("b").innerHTML=newVal==undefined?'':newVal;
            
        }});
    document.getElementById("a").addEventListener("keyup",function (e) {obj.val = e.target.value;})
    
    展开全文
  • 反馈神经网络

    2020-07-27 14:48:44
    典型的反馈神经网络有:Hopfield网络,Elman网络,CG网络模型,盒中脑(BSB)模型和双向联想记忆(BAM)等。在这个阶段我学习的是前两个模型。 Hopfield网络 Hopfield网络分为离散型和连续型两种模式,DHNN 和CHNN

    前面的总结

    单层感知器,线性神经网络,BP网络与径向基网络都属于前向神经网络。在这种网络中,各层神经元节点接收前一层输入的数据,经过处理输出到下一层,数据正向流动,没有反馈连接。前向网络的输出仅由当前的输入和网络经过多次训练后得到的最终的权值决定的。

    反馈神经网络

    典型的反馈神经网络有:Hopfield网络,Elman网络,CG网络模型,盒中脑(BSB)模型和双向联想记忆(BAM)等。在这个阶段我学习的是前两个模型。

    Hopfield网络

    Hopfield网络分为离散型和连续型两种模式,DHNN 和CHNN。 最初提出的Hopfield网络是离散网络,输出是只能取0和1。分别表示是神经元的抑制和兴奋状态。
    在这里插入图片描述
    xi为输入神经元,没有实际功能,即无函数计算。
    yi为输出神经元,其功能是使用阙值函数对计算结果进行二值化。即前面在单层感知器使用过的函数。
    bi为中间层,输入层和中间层之间的存在连接权值为Wij,中间层的神经元之间若有连接,则有连接权值为Wii。
    b为偏置。
    于是有t时刻时:
    在这里插入图片描述
    输出y的值(t+1)时刻时:
    在这里插入图片描述

    网络的稳定性

    Hopfield网络按神经动力学的方式运行,工作过程为状态的演化过程,对于给定的初始状态,按“能量”减少的方式演化,最终达到稳定状态。
    对于反馈神经网络来说,稳定性是至关重要的性质,但是反馈网络不一定都能收敛。网络从初态Y(0)开始,经过有限次递归之后,如果状态不再发生变化,即y(t+1)=y(t),则称该网络是稳定的。
    对于不稳定系统往往是从发散到无穷远的系统,对于离散网络来说,由于输出只能取二值化的值,因此不会出现无穷大的情况,此时,网络出现有限幅度的自持振荡,在有限个状态中反复循环,称为有限环网络。在有限环网络中,系统在不确定的几个状态中循环往复。系统也不可能收敛于一个确定的状态,而是在无限多个状态之间变化,但是轨迹并不发散到无穷远,这种现象称为混沌。
    稳定的数学定义:
    在这里插入图片描述
    然后系统的行为用关于状态的微分方程来描述:
    在这里插入图片描述
    对于一个稳定状态的系统来说就是:
    在这里插入图片描述
    平衡态记为:
    在这里插入图片描述
    这里需要使用一个极限的思想:
    若对任意的正数σ,存在T>0,当t>T时,有在这里插入图片描述
    可以用这个去理解稳定的数学含义。
    而且如果Hopfiled网络是稳定的,则称一个或若干个稳定的状态为网络的吸收子,能够最终演化为该吸收子演化的初始状态的集合,称为该吸收子的吸收域。
    在这里插入图片描述
    这里就存在一个演化过程:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    设计网络

    Hopfield网络可以用于联想记忆,因此又称联想记忆网络,于人脑的联想记忆功能类似。分为两个阶段:
    ①记忆阶段:
    在记忆阶段中,外界输入数据,是系统自动调整网络的权值,最终用合适的权值使系统具有若干个的稳定状态,即吸收子。其吸收域半径定义为吸收子所能吸收的状态的最大距离。吸收域半径越大,说明联想能力越强。联想记忆网络的记忆容量定义为吸收子的数量。
    ②联想阶段:
    在这里插入图片描述
    网络中神经元的个数与输入向量长度相同。初始化完成后,根据下式反复迭代,直到神经元的状态不再发生变化为止,此时输出的吸引子就是对应于输入u进行联想的返回结果
    在这里插入图片描述
    t时刻的输出等于(t+1)的输入。
    学习算法:
    外积法
    在这里插入图片描述
    伪逆法
    在这里插入图片描述
    暂时还不能很好的理解,上述都是关于离散Hopfield网络的定义,关于连续网络,它更多是使用电子硬件来实现的,我暂时学习的是计算机控制

    Elman神经网络

    前辈牛人们根据语音处理问题提出了Elman神经网络。基本的Elman神经网络由输入层,隐含层,连接层和输出层组成。与BP网络相比,在结构上多了一个连接层,用于构成局部反馈。连接层的传递函数为线性函数,但是函数组成中存在延迟单元,因此连接层可以记忆过去的状态,并在下一时刻与网络的输入一起作为隐含层的输入,使得网络具有动态记忆的功能 。
    在这里插入图片描述
    在这里插入图片描述
    我主要就学习上述提到的定义

    相关工具箱函数的学习

    神经网络工具箱

    net=hewhop(T);生成一个离散的Hopfield网络
    输入参数是一个RxQ矩阵,包含Q个长度为R的向量。
    
    A=satlin(N)      饱和线性传递函数
    satlin函数是神经网络的传输函数,函数只有一个输入函数N,是一个SXQ矩阵,包含Q个长度为s的向量。
    
    A=satlin(N)  对称饱和线性传递函数
    
    net=newlm(P,T,[S1....SN],[TF1....TFN],BTF,BLF,PF)
    P:输入向量
    T;目标向量
    si:隐含层神经元的个数
    TFi:传递函数
    BTF:反向传播网络的训练函数
    BLF:反向传播权值/阙值学习函数
    PF:性能函数 
    

    这些都是属于工具箱函数,我们看看就行。

    实例

    在二维平面上定义两个平衡点:[1,-1]与[-1,1]。使所有的输入向量经过迭代最后都收敛到这两个点。

    c1=[-1,1];                 %设置2个吸引子
    c2=[1,-1];
    w11=1/2*(c1(1)*c1(1)+c2(1)*c2(1));   %外积法计算权值
    w12=1/2*(c1(1)*c1(2)+c2(1)*c2(2));
    w21=1/2*(c1(2)*c1(1)+c2(2)*c2(1)); 
    w22=1/2*(c1(2)*c1(2)+c2(2)*c2(2)); 
    w=[0   w12;
      w21  0 ];          %权值矩阵主对角线元素为0 这里的话暂时不考虑阙值b
    b=[0 0];
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %先调整第一个隐含层神经元的状态,按照串行运行规则用y1与权值矩阵的第一列相乘
    y1=[-1,1];              %初始输入
    y21=y1*w(:,1)+b(1);       %更新第一个神经元,用t时刻的输入乘上权值矩阵中,得到第一神经元的输出为y21,即改变t时刻输入的一个元素
    y22=[y21,y1(2)]*w(:,2)+b(2);   %更新第二个神经元,用t+1时刻的输入乘上权值矩阵中,得到第二神经元的输出为y22,即改变t+1时刻输入的二个元素
    y2=[y21,y22] %最终结果,那么此时建立的系统就记住两个平衡点。
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %下面输入随机数据,观察系统能否收敛到平衡点。
    y0=rand(1,2)*2-1;   %随机生成两个数
    y0(y0>=0)=1;         %二值化这两个数,然后也是按照上面的步骤。
    y11=y0*w(:,1)+b(1);       %更新第一个神经元,用t时刻的输入乘上权值矩阵中,得到第一神经元的输出为y11,即改变t时刻输入的一个元素
    y12=[y11,y0(2)]*w(:,2)+b(2);   %更新第二个神经元,用t+1时刻的输入乘上权值矩阵中,得到第二神经元的输出为y12,即改变t+1时刻输入的二个元素
    y1=[y11,y12] %最终结果,可见达到平衡点[-1,1]
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %再用一组
    y3=[-1,-1];
    y31=y3*w(:,1)+b(1);       %更新第一个神经元,用t时刻的输入乘上权值矩阵中,得到第一神经元的输出为y31,即改变t时刻输入的一个元素
    y32=[y31,y3(2)]*w(:,2)+b(2);   %更新第二个神经元,用t+1时刻的输入乘上权值矩阵中,得到第二神经元的输出为y32,即改变t+1时刻输入的二个元素
    y3=[y31,y32] %最终结果,可见达到平衡点[1,-1]
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    

    以上的过程就是先设定吸引子,然后利用权值学习算法计算权值矩阵,然后选择演化方法是串行还是并行。

    这是关于反馈神经网络的初认识。

    结束

    展开全文
  • 根据简化模型,建立了DC-DC双向变换器在不连续运行模式下的离散映射,给出了系统稳定运行状态下迭代方程和反馈系数的计算公式;根据迭代方程得出电压与反馈系数的分岔波形图。电路仿真和实验结果表明,随着反馈系数的...
  • 4. model将新的数据发送到view,用户得到反馈。 MVP模式: MVP模式将Controller改名为Presenter,同时改变了通信方向。 1. 各部分之间的通信都是双向的。 2. View与Model不发生联系,都通过Presenter传递 3. V

    MVC模式和MVP模式的区别
    MVC模式:

    在这里插入图片描述

    1. MVC的所有通信都是单向的。

    2. view传送指令到controller(用户也可以直接将指令传到controller)。

    3. controller完成业务逻辑后要求model改变状态。

    4. model将新的数据发送到view,用户得到反馈。

    MVP模式:

    MVP模式将Controller改名为Presenter,同时改变了通信方向。

    在这里插入图片描述

    1. 各部分之间的通信都是双向的。

    2. View与Model不发生联系,都通过Presenter传递

    3. View非常薄,不部署任何业务逻辑,称为“被动视图”,即没有任何主动性,而Presenter非常厚,所有逻辑都部署在这里。

    展开全文
  • VUE探索第一篇--双向绑定原理

    千次阅读 2018-07-16 00:01:53
    它借鉴了桌面应用程序MVC的设计思想,Model与View之间通过ViewMode关联,ViewModel负责将Model数据的变化显示到View上,通过将View的改变反馈到Model上这就是我们常说的双向绑定数据机制。 那如何设计MVVM模型...

    一、设计思路

       MVVM框架相对传统的dom操作模式,最大的优点就是数据的双向绑定。它借鉴了桌面应用程序MVC的设计思想,Model与View之间通过ViewMode关联,ViewModel负责将Model数据的变化显示到View上,通过将View的改变反馈到Model上这就是我们常说的双向绑定数据机制。

    那如何设计MVVM模型模型呢。需要解决两个关键问题:

    1、如何知道数据更新。

    2、数据更新后,如何通知变化。

    下面我们就分别介绍下vue是如何实现的,理解了这两点,基本上也就明白了双向绑定的机制。

    二、数据劫持

    在ES5中有Object.defineProperty()方法,它能监听各个属性的set和get方法。

     let data ={name:'tcy'}
      Object.defineProperty(data,'name',{
      	set: function(newValue) {
            console.log('更新了data的name:' + newValue);
        },
        get: function() {
            console.log('获取data数据name');
        }
      })
    data.name="fyn";//更新了data的name:fyn
    data.name;//获取data数据name


    Object.defineProperty()方法,有三个参数,分别为待监听的数据对象,待监听的属性,以及对set,get的监听方法。

    上例中,对data对象的name属性进行监听,当执行"data.name='fyn'"触发set方法,执行"data.name"触发get方法。

    vue正是采用了该方法,对data的属性进行劫持。我们来模拟实现其劫持的过程。

    //模拟vue的data数据
    // var vm = new Vue(
    // {
    //   data:{
    //       name:'tcy',
    //       age:'20'
    //   }
    // }
    // 	)
    let data ={name:'tcy',age:'20'}
    function observe(data){
    	//获取所有的data数据对象中的所有属性进行遍历
        const keys = Object.keys(data)
        for (let i = 0; i < keys.length; i++) {
        	let val = data[keys[i]];
           defineReactive(data, keys[i],val)//为每个属性增加监听
        }
    }
    function defineReactive(obj,key,val){
       Object.defineProperty(obj, key, {
        enumerable: true,//可枚举
        configurable: true,//可配置
        get: function reactiveGetter () {
          //模拟get劫持
          console.log("get劫持");
          return val;
        },
        set: function reactiveSetter (newVal) {
           	//模拟set劫持
         console.log("set劫持,新值:"+newVal);
         val = newVal;
        }
      })
    }
    observe(data);
    data.name="fyn";//set劫持,新值:fyn
    console.log(data.name);//get劫持,fyn

    data模拟vue.data对象,observer中对data的属性进行遍历,调用defineReactive对每个属性的get和set方法进行劫持。

    由此,data数据的任何属性值变化,都可以监听和劫持,上述的第一个问题就解决了。

    那view端的数据变化是如何知道的呢,view端改变数据的组件无外乎input,select等,可以用组件的onchange事件监听,这里就不再重点描述。

    接下来就要解决第二个问题,监听到数据变化后如何通知。

    三、发布与订阅

    vue在双向绑定的设计中,采用的是观察-订阅模式,前面所讲的数据劫持,其实就是为属性创建了一个观察者对象,监听数据的变化。接下来就是创建发布类和订阅类,如下:

    observer,创建数据监听,并为每个属性建立一个发布类。

    Dep是发布类,维护与该属性相关的订阅实例,当数据发生更新时,会通知所有的订阅实例。

    Watcher是订阅类,注册到所有相关属性的Dep发布类中,接受发布类的数据变更通知,通过回调,实现视图的更新。

    下面我们就模式发布和订阅的过程。

    //对象数据
    let data ={name:'tcy',age:'20',sex:'male'};
    //发布器的uid
    let uid=0;
    //发布器
    class Dep{
       constructor () {
          this.id = uid++//发布器的标识,每次加1
          this.subs = []//订阅者集合
        }
        //添加订阅者实例对象
        addSub(watcher){
          this.subs.push(watcher);
        }
        //移除订阅者实例对象
        removeSub (watcher) {
          remove(this.subs, watcher)
        }
        // 依赖收集函数,在 getter 中执行,在 Dep.target 上找到当前 watcher,并添加依赖
       depend() { 
           Dep.target && Dep.target.addDep(this)
        }
        //通知所有订阅者
        notify () {
        	const subs = this.subs.slice()
        	for (let i = 0, l = subs.length; i < l; i++) {
            subs[i].update();//更新
        }
    }
    }
    //记录当前的watcher实例
    Dep.target = null;
    const targetStack = []
    function pushTarget (_target) {
       if (Dep.target) targetStack.push(Dep.target)
    	Dep.target = _target
    }
    function popTarget () {
      Dep.target = targetStack.pop()
    }
    
    //订阅者
    class Watcher{
       constructor (
        vm,//vm数据对象
        expOrFn,//待监听的属性表达式
        cb//监听到变化后的回调函数
        ){
    	this.vm=vm;
    	this.expOrFn = expOrFn;
    	this.cb = cb;
    	this.value= this.get();
        }
       //添加自身订阅者到发布器
       addDep (dep) {
       	dep.addSub(this)
       }
      //通知更新
      update(){
        this.run();
      }
      //实现视图的更新
      run(){
         let oldValue = this.value//更新前数据
         let value =  this.get();//获取最新值
         if(value != oldValue){
          this.cb.call(this.vm);
      }
    }
      //获取value值,并进行依赖收集
       get(){
         //将自身watcher订阅实例设置给Dep.target
         pushTarget(this);
         //这一步很重要,获取属性值,同时将订阅者实例添加到发布器中
          let value = this.expOrFn.call(this.vm);
          //将订阅实例从target栈中取出并设置给Dep.target
          popTarget();
          return value;
      }
    }
    
    function observer(data){
    	//获取所有的属性进行遍历
    	const keys = Object.keys(data)
    	for (let i = 0; i < keys.length; i++) {
    		let val = data[keys[i]];
           defineReactive(data, keys[i],val)//增加监听
       }
    }
    
    
    function defineReactive(obj,key,val){
        //为每个键都创建一个 dep
        let dep = new Dep();
        Object.defineProperty(obj, key, {
        enumerable: true,//可枚举
        configurable: true,//可配置
        get: function reactiveGetter () {
          if (Dep.target) {
          	dep.depend();
          }
          return val;
      },
      set: function reactiveSetter (newVal) {
           	val = newVal;
          dep.notify(); // 通知所有订阅者
      }
    })
    }
    
    
    //第一步,为每个属性创建一个发布器,并设置set,get劫持
    observer(data);
    
    //第二步,创建监听并实现依赖收集
    var watcher = new Watcher(data,() => {
      "name"+data.name + "age"+data.age
    },() => {
      console.log("实现视图更新");
    });
    
    //第三步,数据变化,触发视图更新
    data.name="fyn";//实现视图更新
    data.sex="female";
    
    

    下面简单介绍下这几个类

    1、发布器Dep类

    构造函数中定义了subs集合,保存所有注册的订阅者实例,uid为发布器对象的标识。

    addSub,removeSub方法,添加和移除的订阅者,维护实例集合。

    depend方法,将当前的watcher实例对象添加到subs集合中。这是会涉及到依赖收集,后面会讲到。

    notify方法,遍历subs中所有维护的订阅者实例,并进行更新操作。

    2、订阅者Watcher类,

    在构造函数的入参中设置

    vm-组件对象,即本例的data

    expOrFn--属性或者表达式

    cb--更新视图的回调函数

    在实例化的时候,调用get方法,获取当前的监听属性的值,同时触发该属性的get方法(参见defineReactive的get方法),调用dep.depend()将订阅实例添加上发布器Dep中(记住,这步很重要)

    run方法,收到变化通知,比较数据的前后值,调用cb实现视图的更新。

    3、defineReactive方法

    该方法与前面的比较,总体框架是一致的,但增加了一些代码。

    let dep = new Dep();

    为数据对象中的每个属性建立一个发布器。

    在get发方法中,将订阅者加入到该属性的发布器subs中

    在set中,数据发生变化,调用dep.notify()通知所有的订阅者,最终执行run方法,比较value值是否发生了变化,如果是,则调用cb的回调方法进行视图更新。

    如果上面的分析没看明白,没关系,我们用具体的实例,分析下其调用过程。

    1、为每个属性创建一个发布器,并设置set,get劫持

    执行observer(data);其模型对象如下:

    2、第二步,创建监听,并实现依赖收集

    我们考虑下,模板上有一段代码,"<p>name:{{data.name}},age:{{data.age}}",暂不考虑编译过程,翻译过来,

    "name"+data.name + "age"+data.age

    需要对这个表达式进行监听,我们期望name,age的属性发生任何变化,立即通知模板实现页面的刷新,因为data中还有个sex的属性,这个表达式没有涉及到,所以为了提高效率,这个属性的任何变化,无需实现监,这就是依赖收集的概念。

    我们看下是如何做到的。

    在创建这个实例的过程中,会调用get方法,执行下面一段代码:

    let value = this.expOrFn.call(this.vm);

    它会触发name,age属性的get劫持方法,调用dep.depend方法,将该监听加入到对应属性的dep对象中。模型如下:

    3、数据变化,触发视图更新

    当执行data.name="fyn"时,会被name属性的set方法劫持,调用dep.notify(),该属性的dep对象的subs是有watcher实例的,故执行该watcher实例的updata方法,实现视图更新。

    当执行data.sex="female"时,会被sex属性的set方法劫持,调用dep.notify(),但该属性的dep对象的subs是空值,不会有任何更新。

    整个流程的方法调用示意图:

    四、总结

    本文对vue的数据双向绑定主要流程和代码,以模拟的形式进行解释,vue的实际实现中,还有很多细节考虑,具体可以参考其源码observer目录下的相关文件。

    下一篇:VUE探索第二篇-手脚架(vue-cli)

    展开全文
  • 如果返回消息很快,那么通信过程可以是同步的,所以客户端应用程序阻塞等待反馈。如果请求和回复之间会有延时,请求-回复模式可以在客户端使用标 准.NET技术实现异步调用。在那种情况下,WCF会在发送请求给服务端后...
  • 然后建立基于深度信任网络和回归模型的双向度量模型DM-QSM,将服务描述信息和类似服务历史数据作为训练样本数据集对DM-QSM进行正向训练,再结合用户反馈对DM-QSM进行逆向调优,以实现QoS度量指标权重及其偏好度的...
  • 文章解析 AES AES 加密模式(CBC、ECB、CTR、OCF、CFB) ECB:是一种基础的加密方式,密文被...CFB/OFB:实际上是一种反馈模式,目的也是增强破解的难度。 FCB和CBC的加密结果是不一样的,两者的模式不同,而..
  • 但是,鉴于此存储库的反馈和使用,我将在此开始对其进行维护,并优先解决/实施所提出的问题。 适用于iOS的SimpleTwoWayBinding 需要 MVVM ? 为什么苹果不推荐MVC ? Android最适合MVP吗? 酷的VIPER模式怎么样? ...
  • 如果返回消息很快,那么通信过程可以是同步的,所以客户端应用程序阻塞等待反馈。如果请求和回复之间会有延时,请求-回复模式可以在客户端使用标准.NET技术实现异步调用。在那种情况下,WCF会在发送请求给服务端后...
  • 1.引言目前防盗器市场的主流产品是电子式防盗器,分为单向防盗器和双向防盗器,这两种防盗器都是车主通过遥控器来控制汽车,双向防盗器可以把车辆的真实状况反馈给车主。GPS汽车防盗器依托全球定位系统,
  • 在MVVM模式下,有个双向数据绑定(data-binding)的优势,可以通过viewmodel实时的监听用户操作,也可以将model的改动实时的反馈到界面上。 那么,在传统的js操控DOM的情况下如何实现呢? 下面我们以输入框(input...
  • 设计模式(中介)

    2020-07-14 14:34:40
    再比如利用电子信息技术的互联网,作为一种新媒体,不单可以更高效地把信息传递给用户,而且可以反向地获得用户反馈评论,用户与用户之间亦可以进行沟通,这种全终端双向互通是传统媒体所不能及的。 除此之外,再...
  • MVC和MVVM模式的区别

    万次阅读 2017-12-01 10:48:30
    MVC ,用户操作> View (负责接受用户的输入操作)>Controller(业务逻辑处理)>Model(数据持久化)>View(将结果通过View反馈给用户) 2,MVVM MVVM是将“数据模型数据双向绑定”的思想作为核心,因此在View和...
  • 中介者模式,感觉也没什么好说的,就是字面意思:对复杂对象之间进行管理,但是这个管理是双向的,既可以接受反馈,也能发出指令,实现对象之间联系的解耦合,是对象的行为型模式。故叫做中介者,或者调停者模式。 ...
  • 最近项目在用nginx的Push_stream_module推送模块去实现服务器端向客户端信息的推送,本来只想实现这个单向通信的需求的,可是给客户端推送完消息之后,如果想让客户端给一个反馈,就没办法监听获取到客户端的反馈...
  • 本资源包是金旭亮.NET3.5系列课程中的一部分,包括一个PDF文档和几个VS2008示例项目,主要介绍如何在WCF应用程序中实现各种信息交换模式,包括“请求/应答”,“单向通讯”,“双向通讯”和“事件驱动”。...
  • 中介,作用于多个事物之间充当...再比如利用电子信息技术的互联网,作为一种新媒体,不单可以更高效地把信息传递给用户,而且可以反向地获得用户反馈评论,用户与用户之间亦可以进行沟通,这种全终端双向互通是传...
  • 再比如利用电子信息技术的互联网,作为一种新媒体,不单可以更高效地把信息传递给用户,而且可以反向地获得用户反馈评论,用户与用户之间亦可以进行沟通,这种全终端双向互通是传统媒体所不能及的。  除此之外,...
  • 【什么是敏捷开发?】资深程序员之路(5)--agile开发 敏捷开发(scrum, agile)相对于瀑布流开发(waterfull)更适合现在快节奏的...好处:随时保持和客户的交互(双向反馈),确保开发更符合客户实际业务需求。 ...
  • 分析单端恒压控制下双向DC/DC变换器在冲、放电模式下的状态方程,建立相应的精准反馈线性化模型。针对直流变换器固有开关特性,设计滑模变结构控制算法。仿真结果表明,单端恒压下变换器的精准反馈线性化滑模控制...
  • MVC与MVP的区别

    2020-11-12 15:42:31
    4. model将新的数据发送到view,用户得到反馈。 MVP模式: MVP模式将Controller改名为Presenter,同时改变了通信方向。 1. 各部分之间的通信都是双向的。 2. View与Model不发生联系,都通过Presenter传递 3. Vie
  • 沟通第一节 亲密关系沟通的两大心法一. 把事情放进关系里二. 把沟通还原...双向消极3. 不同但有用4. 不同但无用5. 主动跳出负面关系模式第三节 男女沟通小技巧一. 女性要有话直说二. 男人要学会反馈三. 不要和自己...
  • mvc mvp mvvm 组图

    2021-02-20 16:54:02
    3、Model 将新的数据发送到 View,用户得到反馈 MVP模式: MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。 1、 各部分之间的通信,都是双向的。 2、View 与 Model 不发生联系,都通过 Presenter ...
  • 而内容电商的兴起为制造商带来新的需求市场,通过 网红、KOL 与 MCN 机构实现与消费者互动与双向反馈,提升消费者对产品的兴趣爱好、对 时尚品味的感知能力以及选款能力,并实现面向粉丝群体的预售定制,精准、快速...

空空如也

空空如也

1 2 3 4
收藏数 61
精华内容 24
关键字:

双向反馈模式