您好,欢迎访问一九零五行业门户网

原生js实现MVVM框架的基本原理详解

本篇文章给大家带来的内容是关于原生js实现mvvm框架的基本原理详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
在前端页面中,把 model 用纯 js 对象表示,view 负责显示,两者做到了最大化的分离
把 model 和 view 关联起来的就是 viewmodel。viewmodel 负责把 model 的数据同步到 view 中显示出来,还负责把 view 的修改同步回 model。
mvvm 的设计思想:关注 model 的变化,让 mvvm 框架去自动更新 dom 的状态,从而把开发者从操作 dom 的繁琐步骤中解脱出来。
了解了 mvvm 思想后,自己用原生 js 实现一个 mvvm 框架。
实现 mvvm 框架前先来看几个基本用法:
object.defineproperty普通声明对象,定义和修改属性
let obj = {}obj.name = 'zhangsan'obj.age = 20
用objectdefineproperty声明对象
语法:
object.defineproperty(obj,prop,descriptor)
obj:要处理的目标对象
prop:要定义或修改的属性的名称
descriptor:将被定义或修改的属性描述符
let obj = {}object.defineproperty(obj,'age',{    value = 14,})
咋一看有点画蛇添足,这不很鸡肋嘛
别急,往下看
描述符descriptor有两种形式:数据描述符和存储描述符,他们两个共有属性:
configurable,是否可删除,默认为false,定义后无法修改
enumerable,是否可遍历,默认为false,定以后无法修改
共有属性configurable设置为false时,其内部属性无法用delete删除;如要删除,需要把configurable设置为true。
let obj = {}object.defineproperty(obj,'age',{    configurable:false,    value:20,})delete obj.age         //false
enumerable设置为false时,其内部属性无法遍历;如需遍历,要把enumerable设置为true
let obj = {name:'zhangsan'}object.defineproperty(obj,'age',{    enumerable:false,    value:20,})for(let key in obj){    console.log(key)    //name}
数据描述符value:该属性对应的值,默认为undefined。
writable:当且紧当为true时,value才能被赋值运算符改变。默认为false。
let obj = {}object.defineproperty(obj,'age',{    value:10,    writable:false})obj.age = 11obj.age        //10
writable和configurable的区别是前者是value能否被修改,后者是value能否被删除。
存储描述符get():一个给属性提供getter的方法,默认为undefined。
set():一个给属性提供setter的方法,默认为undefined。
let obj = {}let ageobject.defineproperty(obj,'age',{    get:function(){        return age    },    set:function(newval){        age = newval    }})obj.age = 20obj.age        //20
当我调用obj.age时,其实是在向obj对象要age这个属性,它会干嘛呢?它会调用obj.get()方法,它会找到全局变量age,得到undefined。
当我设置obj.age = 20时,它会调用obj.set()方法,将全局变量age设置为20。
此时在调用obj.age,得到20。
注意:数据描述符和存储描述符不能同时存在,否则会报错
let obj = {}let ageobject.defineproperty(obj,'age',{    value:10,        //报错    get:function(){        return age    },    set:function(newval){        age = newval    }})
数据拦截使用object.defineproperty来实现数据拦截,从而实现数据监听。
首先有一个对象
let data = {    name:'zhangsan',    friends:[1,2,3,4]}
下面写一个函数,实现对data对象的监听,就可以在内部做一些事情
observe(data)
换句话说,就是data内部的属性都被我们监控的,当调用属性时,就可以在上面做些手脚,使得返回的值变掉;当设置属性时,不给他设置。
当然这样做很无聊,只是想说明,我们可以在内部做手脚,实现我们想要的结果。
那observe这个函数应该怎么写呢?
function observe(data){    if(!data || typeof data !== 'object')return //如果 data 不是对象,什么也不做,直接跳出,也就是说只对 对象 操作    for(let key in data){    //遍历这个对象        let val = data[key]    //得到这个对象的每一个`value`        if(typeof val === 'object'){    //如果这个 value 依然是对象,用递归的方式继续调用,直到得到基本值的`value`            observe(val)        }        object.defineproperty(data,key,{    //定义对象            configurable:true,    //可删除,原本的对象就能删除            enumerable:true,    //可遍历,原本的对象就能遍历            get:function(){                console.log('这是假的')    //调用属性时,会调用 get 方法,所以调用属性可以在 get 内部做手脚                //return val    //这里注释掉了,实际调用属性就是把值 return 出去            },            set:function(newval){                console.log('我不给你设置。。。')    //设置属性时,会调用 set 方法,所以设置属性可以在 set 内部做手脚                //val = newval    //这里注释掉了,实际设置属性就是这样写的。            }        })    }}
注意两点:
我们在声明let val = data[key]时,不能用var,因为这里需要对每个属性进行监控,用let每次遍历都会创建一个新的val,在进行赋值;如果用var,只有第一次才是声明,后面都是对一次声明val进行赋值,遍历结束后,得到的是最后一个属性,显然这不是我们需要的。
get方法里,return就是前面声明的val,这里不能用data[key],会报错。因为调用data.name,就是调用get方法时,得到的结果是data.name,又继续调用get方法,就随变成死循环,所以这里需要用一个变量来存储data[key],并将这个变量返回出去。
观察者模式一个典型的观察者模式应用场景——微信公众号
不同的用户(我们把它叫做观察者:observer)都可以订阅同一个公众号(我们把它叫做主体:subject)
当订阅的公众号更新时(主体),用户都能收到通知(观察者)
用代码怎么实现呢?先看逻辑:
subject 是构造函数,new subject()创建一个主题对象,它维护订阅该主题的一个观察者数组数组(举例来说:subject 是腾讯推出的公众号,new subject() 是一个某个机构的公众号——新世相,它要维护订阅这个公众号的用户群体)
主题上有一些方法,如添加观察者addobserver、删除观察者removeobserver、通知观察者更新notify(举例来说:新世相将用户分为两组,一组是忠粉就是 addobserver,一组是黑名单就是:removeobserver,它在忠粉组可以添加用户,可以在黑名单里拉黑一些杠精,如果有福利发放,它就会统治忠粉里的用户:notify)
observer 是构造函数,new observer() 创建一个观察者对象,该对象有一个update方法(举例来说:observer 是忠粉用户群体,new observer() 是某个具体的用户——小王,他必须要打开流量才能收到新世相的福利推送:updata)
当调用notify时实际上调用全部观察者observer自身的update方法(举例来说:当新世相推送福利时,它会自动帮忠粉组的用户打开流量,这比较极端,只是用来举例)
es5 写法:function subject(){    this.observers = []}subject.prototype.addobserver = function(observer){    this.observers.push(observer)}subject.prototype.removeobserver = function(observer){    let index = this.observers.indexof(observer)    if(index > -1){        this.observers.splice(index,1)    }}subject.prototype.notify = function(){    this.observers.foreach(observer=>{        observer.update()    })}function observer(name){    this.name = name    this.update = function(){        console.log(name + ' update...')    }}let subject = new subject()    //创建主题let observer1 = new observer('xiaowang')    //创建观察者1subject.addobserver(observer1)    //主题添加观察者1let observer2 = new observer('xiaozhang')    //创建观察者2subject.addobserver(observer2)    //主题添加观察者2subject.notify()    //主题通知观察者/**** 输出 *****/hunger update...valley update...
es6 写法:class subject{    constructor(){        this.observers = []    }    addobserver(observer){        this.observers.push(observer)    }    removeobserver(observer){        let index = this.observers.indexof(observer)        if(index > -1){            this.observers.splice(index,1)        }    }    notify(){        this.observers.foreach(observer=>{            observer.update()        })    }}class observer{    constructor(name){        this.name = name        this.update = function(){            console.log(name + ' update...')        }    }}let subject = new subject()    //创建主题let observer1 = new observer('xiaowang')    //创建观察者1subject.addobserver(observer1)    //主题添加观察者1let observer2 = new observer('xiaozhang')    //创建观察者2subject.addobserver(observer2)    //主题添加观察者2subject.notify()    //主题通知观察者/**** 输出 *****/hunger update...valley update...
es5 和 es6 写法效果一样,es5 的写法更好理解,es6 只是个语法糖
主题添加观察者的方法subject.addobserver(observer)很繁琐,直接给观察者下方权限,给他们增加添加进忠粉组的权限
class observer{  constructor() {    this.update = function() {        console.log(name + ' update...')    }  }  subscribeto(subject) {    //只要用户订阅了主题就会自动添加进忠粉组    subject.addobserver(this)    //这里的 this 是 observer 的实例  }}let subject = new subject()let observer = new observer('lisi')observer.subscribeto(subject)  //观察者自己订阅忠粉分组subject.notify()/****** 输出 *******/lisi update...
mvvm 框架的内部基本原理就是上面这些。
相关推荐:
js实现一个简单的mvvm框架示例分享
php的mvc框架 深入解析_php教程
以上就是原生js实现mvvm框架的基本原理详解的详细内容。
其它类似信息

推荐信息