MV*模式

  1. MVC
  2. MVP
  3. MVVM

1 MVC

一个利用分为三局部

  1. 模型 (Model):数据保留

    应用程序的数据、管制与批改这些数据的业务规定
    Model扭转时:告诉View,为View提供查问Model相干状态的能力,为Controller提供拜访封装在Model外部的应用程序性能的能力。
  2. 视图 (View):用户界面

    组织Model的内容
    Model扭转时:View负责保护数据体现的一致性,同时View将用户的申请告诉Controller
  3. 控制器 (Controller):业务逻辑

    应用程序的行为
    解释来自View的用户申请,把申请映射为行为,再由Model实现这些行为。

结构图:

  • View传送指令到Controller
  • Controller实现业务逻辑后,要求Model扭转状态
  • Model将新的数据发送到View,用户失去反馈

    承受指令的形式
    由View承受指令,传递给Controller
    Controller间接承受指令

2 MVP

  1. 模型(Model):提供数据
  2. 视图(View):用户界面
  3. 示意器(Presenter):逻辑的解决

结构图

  • View与Model无分割,都通过Presenter传递
  • View中不部署任何业务逻辑 - 被动视图
  • 所有逻辑都部署在Presenter
与MVC的区别
View不能间接从Model中读取数据

3 MVVM

基本上与MVP模式统一

  1. 模型(Model):保留数据
  2. 视图(View):用户界面
  3. 数据驱动(View-Model):业务逻辑

    VM负责转换Model中的数据对象

结构图

  • 操作View时,ViewModel感知变动,告诉Model产生相应的变动,若Model扭转时,ViewModel感知变动,告诉View进行更新
  • ViewModel与View双向数据绑定,Model通过接口申请数据交互,承前启后。

双向数据绑定

  1. Vue2:Object.defineProperty()
  2. Vue3:Proxy代理

1 Vue2双向绑定实现

Object.defineProperty(obj,prop,description)

原理简析,不做依赖收集
/** * 对Object.defineProperty()进行封装 */function defineReactive(obj, key, value) {    //递归 - 对象的属性仍是对象    observe(value);    //变动侦测    Object.defineProperty(obj, key, {        get() {            return value;        },        set(newVal) {            if (newVal !== value) {                updateView();                value = newVal;                observe(newVal)            }        }    })}/** * 对一个对象所有属性的变动侦测 */function observe(target) {    //非对象,间接返回    if (typeof target !== 'object') {        return target;    }    //将每个属性转换为getter和setter模式    for (let key in target) {        defineReactive(target, key, target[key])    }}//模仿更新视图的办法function updateView() {    console.log("更新视图");}
通过间接调用observe侦测对象属性的变动

存在的问题

  1. 性能较差
  2. 对象上新增属性无奈侦测
  3. 扭转数组的length属性无奈被侦测

2 Vue3双向绑定实现

Proxy是一种能够拦挡并扭转底层JavaScript引擎操作的包装器,性能更优异
数组能够像对象一样触发get与set
【js】代理与反射(Proxy/Reflect)
【阮一峰】ES6规范-Proxy

原理简析,不做依赖收集

根本流程

cosnt o = {name:"张三"}const proxy = new Proxy(o,{    get(target,key,receiver){        console.log("读取属性值")    },    set(target,key,value,receiver){        console.log("设置属性值")    },    deleteProperty(target,key){        console.log("删除属性")    }})proxy.name; //读取属性值proxy.name = "李四";//设置属性值delete proxy[name] ;//删除属性

自定义的业务逻辑

//判断是否是对象function isObj(val) {    return val !== null && typeof val === "object"}//判断以后对象是否有指定属性function hasOwn(target, key) {    return target.hasOwnProperty(key)}//存储代理信息const toProxy = new WeakMap()const toRaw = new WeakMap()/** *创立响应式对象 */function createReactiveObj(target) {    //指标不是对象,间接返回target    if (!isObj(target)) {        return target    }    const proxy = toProxy.get(target)    //如果指标对象已被代理,间接返回代理对象    if (proxy) {        return proxy    }    //如果指标对象是代理对象,并有对应的真的对象,间接返回    if (toRaw.has(target)) {        return target    }    //生成代理对象    const observed = new Proxy(target, {        get(target, key, receiver) {            console.log("读取值");            const result = Reflect.get(target, key, receiver)            //为返回值增加代理            return isObj(result) ? reactive(result) : result        },        set(target, key, value, receiver) {            //判断指标对象是否曾经存在该属性            const hasProperty = hasOwn(target, key)            const oldVal = Reflect.get(target, key)            if (!hasProperty) {                console.log("新增属性");            } else if (oldVal !== value) {                console.log("批改属性");            }            return Reflect.set(target, key, value, receiver)        },        deleteProperty(target, key) {            console.log("删除值");            return Reflect.deleteProperty(target, key)        }    })    //增加指标对象与代理对象到Map    toProxy.set(target, observed)    toRaw.set(observed, target)    return observed}//响应式入口function reactive(target) {    return createReactiveObj(target)}

与根本流程相比,自定义实现的性能

  • 解决多层对象侦测的问题,

    get中判断
  • 屡次代理

    用WeakMap存储代理信息,判断是否曾经被代理,或者自身是代理对象
  • 数组push产生两次get,一次属性一次length

    新旧值比照,在push元素后length曾经扭转,第二次的get不对length做任何批改,防止了增加一个值,视图更新两次

Proxy的handler中还能够写很多办法,以满足简单的业务