Vue2.X的官方文档已经对深度响应原理进行了讲解。简单的说就是数据被修改后,在es5中被Object.defineProperty和setter拦截。通知watcher,watcher渲染函数,这个过程需要创建一个新的虚拟dom节点,对比旧的虚拟dom节点,比对之后打补丁,把补丁放到真实的dom结构中,然后更新真实的dom,视图发生了变化。Object.defineProperty()数据劫持/数据代理使用javascript引擎给出的函数来检测对象属性的变化。Object.defineProperty()方法会直接在一个对象上定义一个新的属性,或者修改一个对象已有的属性,并返回这个对象。varobj={};Object.defineProperty(obj,'a',{value:3})Object.defineProperty(obj,'b',{value:5})console.log(obj)//{a:3,b:5}console.log(obj.a,obj.b)//35Object.defineProperty()可以设置额外的隐藏属性Object.defineProperty(obj,'a',{//value:3,get(){},//是否可写:true})Object.defineProperty()实际上是通过自己的getter函数(读取)和setter函数(设置)对数据进行操作的:Object.defineProperty(obj,'a',{//getter函数get(){console.log(ole.log('访问一个属性');return7;},//setterfunctionset(nVal){console.log('修改一个属性为'+nVal)}})console.log(obj.a);//7obj.a=10;console.log(obj.a);//7从上面的例子来看,访问obj的a属性时,值为7,修改后a属性的值,从打印结果可以看出确实执行了setter函数,但是新的值并没有赋值给getter的返回值,此时getter和setter缺少一个连接桥:变量,所以上面的代码稍微改变一下:vartemp='';Object.defineProperty(obj,'a',{//getterfunctionget(){console.log(ole.log('访问属性');返回温度;},//setter函数set(nVal){console.log('修改属性为'+nVal);温度=nVal;}})C控制台日志(obj.a);//7obj.a=10;console.log(obj.a);//从10到这里,Object.defineProperty()的用法已经很清楚了,接下来要做的就是如何让它更漂亮优雅~defineReactivefunctionvarobj={};functiondefineReactive(data,key,val){//val为defineReactive函数中的getter和setter函数创建一个闭包环境,这样就不需要再声明一个TemporaryvariableObject.defineProperty(data,key,{//enumerableenumerable:true,//可以配置,比如可以删除configurable:true,//getterfunctionget(){console.log(ole.log('Accessaproperty');returnval;},//setterfunctionset(nVal){console.log('修改属性为'+nVal);if(nVal===val)return;val=nVal;}})}defineReactive(obj,'a',10);conso.log(obj.a);//10obj.a++;//赋值时调用setter函数console.log(obj.a);//11这段代码解决了变量的问题,但是这个例子只满足单层对象,所以像obj:{a:{m:{n:5}}}这样复杂结构的数据需要逐层遍历,递归调用Object.defineProperty()来处理~varobj={a:{m:{n:5}}}访问obj.a.m.n属性,你可以't每次都设置一个属性,所以当有结构复杂的对象时,defineReactive函数需要做参数判断:functiondefineReactive(data,key,val){if(arguments.length==2){val=data[key]}...}defineReactive(obj,'a')console.log(obj.a.m.n);//当要访问obj.a.m.n属性时,只能访问a级别的递归检测对象的所有属性。对于obj的a.m.n属性,需要递归实现Object.defineProperty()。这时候创建一个类Observer,主要是将普通对象转换成任意属性都可以检测的工具类:stateDiagram-v2Observer(observer)-->将普通对象转换成对象Observer,其每一层的属性都是responsive(可检测).jsexportdefaultclassObserver{constructor(value){//每个Observer实例都有一个depthis.dep=newDep()//对于实例(this,构造函数中的this不代表class本身,而是代表一个实例)添加了__ob__属性,值为value(这次是new的一个实例)def(value,'__ob__',this,false)//console.log('IamanObserverconstructor',value)//Observer类的作用:将一个普通对象转换为一个对象,其每一层的属性都是响应式的(可以检测到)//判断是数组还是对象if(Array.isArray(value)){//如果是数组,肯定很强,把这个数组的原型指向arrayMethods//setPrototypeOf强制定义值的原型Object.setPrototypeOf(value,arrayMethods)//使这个数组可观察this.observeArray(value)}else{this.walk(value)}}//遍历walk(value){for(letkinvalue){defineReactive(value,k)}}//特殊数组遍历observeArray(arr){for(leti=0,l=arr.length;i
