前言Vue3.0是2019年10月5日发布的,现在2020年了,估计是Vue3正式版.0很快就会出来。2.0和3.0的变化也比较大,结构上:2.0用的是Flex,3.0用的是TypeScript。性能:3.0优化了VirtualDom的算法。响应式原理:2.0使用Object.defineProperty,3.0使用Proxy...Vue2.0和Vue3.0实现了Vue2.0的原理Vue2.0通过Object劫持各个属性实现了MVVM(双向数据绑定)的原理。definePropertySetters和getters在数据变化时向订阅者发布消息,触发相应的监听回调。Vue官网也给出了解释:Vue3.0基于ES6实现响应式:ProxyVue2.0和Vue3.0的区别如下:Vue2.0基于Object.defineProperty,不具备监听数组的能力,需要重新定义数组的原型来实现Responsive。Object.defineProperty无法检测对象属性的增减。由于Vue在初始化实例时会对属性进行getter/setter转换,因此所有属性都必须存在于数据对象上,Vue才能将其转换为响应式。深度监控需要一次性递归,对性能影响比较大。Vue3.0基于Proxy和Reflect,<可以原生监控数组,可以监控对象属性的增删改查。不需要一次性遍历数据的属性,可以显着提高性能。因为Proxy是ES6的新属性,部分浏览器还不支持,只兼容IE11。Vue2.x实现响应式下面是基于Object.defineProperty,一步步实现Vue2.0简易版。由于Object.defineProperty不能监听数组,所以数组类型实现了响应式,需要进行处理。如果是数组类型,重写数组的原型方法('push','pop','shift',unshift)//重新定义数组的原型,Object.defineProperty没有监听数组的方法constoldArrayProperty=Array.prototype;constarrProto=Object.create(oldArrayProperty);["push","pop","shift","unshift","splice"].forEach(methodName=>(arrProto[methodName]=function(){updateView();oldArrayProperty[methodName].call(this,...arguments);}))深入监控传入的数据属性,判断是对象还是数组。functionobserver(target){if(typeoftarget!=='object'||target===null){returntarget}//如果是数组类型,重写数组原型的方法("push","pop","shift","unshift","splice")if(Array.isArray(target)){target.__proto__==arrProto;}//如果是对象,遍历对象的所有属性,使用Object.defineProperty把这些属性全部转换为getter/setterfor(letkeyintarget){defineReactive(target,key,target[key])}}核心APIObject.defineProperty,将传入的属性转换为getter/setterfunctiondefineReactive(target,key,value){//如果对象的层数较多,则再次调用观察者监控方法,实现深度监控。观察者(价值);Object.defineProperty(target,key,{get(){returnvalue;},set(newValue){//设置value的时候,还需要深度监听observer(value);if(newValue!==value){value=newValue;//数据驱动视图,如果数据发生变化,调用视图更新方法。对应Vue就是执行VDOMupdateView();}}})}数据更新会触发视图更新,这是MVVM的绑定原理,会涉及到将Vue模板编译成render函数,执行VirtualDom、DiffAlgorithms、Vnode等东西。functionupdateView(){console.log('viewupdate')}5。useconstdata={name:"zhangsan",age:20,info:{address:"北京"//需要深度监控},nums:[10,20,30]};观察者(数据);Vue3.0实现响应式Vue3.0是基于Proxy做数据劫持代理,可以原生支持响应式数组,无需重写数组的原型,还可以直接支持增删属性,比Object.defineProperty更清晰Vue2.x的。核心代码(很少)constproxyData=newProxy(data,{get(target,key,receive){//只处理自身的属性(非原型)constownKeys=Reflect.ownKeys(target)if(ownKeys.includes(key)){console.log('get',key)//监听}constresult=Reflect.get(target,key,receive)returnresult},set(target,key,val,reveive){//重复数据,未处理constoldVal=target[key]if(val==oldVal){returntrue}constresult=Reflect.set(target,key,val,reveive)returnresult},//删除属性deleteProperty(target,key){constresult=Reflect.deleteProperty(target,key)returnresult}})useconstdata={name:"zhangsan",age:20,info:{address:"Beijing"//需要深度监控},nums:[10,20,30]};这样做就可以了,不需要申报。Proxy会直接监听数据的内容,非常简单方便。唯一的缺点是部分浏览器不兼容Proxy,无法破解,所以目前只兼容IE11。所有源代码都可以直接复制到chrome浏览器的控制台直接调试打印。Vue2.0functiondefineReactive(target,key,value){//深度监控observer(value);Object.defineProperty(target,key,{get(){returnvalue;},set(newValue){//深度监控observer(value);if(newValue!==value){value=newValue;updateView();}}});}functionobserver(target){if(typeoftarget!=="object"||target===null){返回目标;}if(Array.isArray(target)){target.__proto__=arrProto;}for(letkeyintarget){defineReactive(target,key,target[key]);}}//重新定义数组原型constoldAddrayProperty=Array.prototype;constarrProto=Object.create(oldAddrayProperty);["push","pop","shift","unshift","splug"].forEach(methodName=>(arrProto[methodName]=function(){updateView();oldAddrayProperty[methodName].call(this,...arguments);}));//视图更新函数updateView(){console.log("视图更新");}//声明响应对象constdata={name:"zhangsan",age:20,info:{address:"北京"//需要深度监控},nums:[10,20,30]};//执行responsiveobserver(data);Vue3.0constproxyData=newProxy(data,{get(target,key,receive){//只处理自身的属性(非原型)constownKeys=Reflect.ownKeys(target)if(ownKeys.includes(key)){console.log('get',key)//监听}constresult=Reflect.get(target,key,receive)returnresult},set(target,key,val,reveive){//重复数据,做不处理constoldVal=target[key]if(val==oldVal){returntrue}constresult=Reflect.set(target,key,val,reveive)console.log('set',key,val)returnresult},deleteProperty(target,key){constresult=Reflect.deleteProperty(target,key)console.log('deleteproperty',key)console.log('result',result)returnresult}})//声明对象为了响应,Proxy会自动代理constdata={name:"zhangsan",age:20,info:{address:"Beijing"//需要深度监控},nums:[10,20,30]};
