面试官:请你简单的说说什么是Vue的响应式。
小明:mvvm就是视图模型模型视图,只有数据改变视图就会同时更新。
面试官:说的很好,回去等通知吧。
小明:....
Vue响应式原理
先看官方的说法
简单理解就是实例data,Vue通过遍历data中所有对象通过Observer劫持监听所以属性,然后数据一旦发生变化,就通知编译解析变化,更新视图。
首先创建一个data,需要将data变成响应式数据,创建Observer 函数传值data,如果data不是一个对象或者是空就不用处理直接return
<script> function Observer(targer){ if(typeof targer !== 'object' || targer ===null){ return targer } } const data = { name:'海海', age:18, info:{ address:'广州' }, fava:[1,2,3,4,5] } Observer(data) </script
其他的处理
这里只处理数组,其他
判断是否等于数组,如果等于,如果不等于就循环target,声明响应式函数 defineReactive
传值targer,循环的key和targer[key],然后在 defineReactive调用我们的 Object.defineProperty
function Observer(targer){ if(typeof targer !== 'object' || targer ===null){ return targer } if(Array.isArray(targer)) { // 数组 }else{ for(let key in targer){ // 响应式数据的函数 defineReactive(targer,key,targer[key]) } } }
Object.defineProperty
(Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。)
传入我们的参数
拿到get set方法
get
初始值 直接return 我们的value
set
第一个参数是最新的值 newValue
判断如果我们传入的value和newValue不相等,那么就把newValue赋值给value
function defineReactive(targer,key,value){ Object.defineProperty(targer,key,{ get(){ return value }, set(newValue){ if(newValue !== value) { value =newValue } } }) }
那么问题又来了,如果是一个对象需要监听,我们刚刚的操作只监听到了第一层,如果监听的内容是上面的info就相当于监听了整个对象,答案也很简单,我们只需要在调用defineReactive的时候在调用一次Observer在进入一次循环,当不是object就自动结束了
function defineReactive(targer,key,value){ Observer(value) Object.defineProperty(targer,key,{ get(){ return value }, set(newValue){ if(newValue !== value) { value =newValue } } }) }
视图更新
我们这里在模仿一下视图更新 定义函数 updataView
function updataView(){ console.log('视图更新了') }
调用
显示视图更新。
数组
先定义一个值 oldArrayProperty 然后将Array.prototype赋值给oldArrayProperty,
然后针对原型对象创建 Object.create()
定义一个 arrProto 来接收。
然后声明数组 ['push','pop','unshift','shift','reverse','sort','splice'] 进行循环
const oldArrayProperty =Array.prototype const arrProto = Object.create(oldArrayProperty) const fn = ['push','pop','unshift','shift','reverse','sort','splice'] fn.forEach((method)=>{ arrProto[method] = function(){ } })
然后调用更新视图 updataView return 将oldArrayProperty对应的方法匹配上return出来
const oldArrayProperty =Array.prototype const arrProto = Object.create(oldArrayProperty) const fn = ['push','pop','unshift','shift','reverse','sort','splice'] fn.forEach((method)=>{ arrProto[method] = function(){ updataView() return oldArrayProperty[method].call(this,...arguments) } })
然后回到Observer方法中,将arrProto赋值给 targer的__proto__原型链上,最后在将targer循环调用Observer,进行数据更新。
if(Array.isArray(targer)) { // 数组 targer.__proto__ =arrProto for(let i=0;i<targer.length;i++) { Observer(targer[i]) } }
测试
到这里我们的监听数据变化并自动更新就完成了。
完整代码
<script> function defineReactive(targer,key,value){ Observer(value) Object.defineProperty(targer,key,{ get(){ return value }, set(newValue){ if(newValue !== value) { value =newValue updataView() } } }) } const oldArrayProperty =Array.prototype const arrProto = Object.create(oldArrayProperty) const fn = ['push','pop','unshift','shift','reverse','sort','splice'] fn.forEach((method)=>{ arrProto[method] = function(){ updataView() return oldArrayProperty[method].call(this,...arguments) } }) function Observer(targer){ if(typeof targer !== 'object' || targer ===null){ return targer } if(Array.isArray(targer)) { // 数组 targer.__proto__ =arrProto for(let i=0;i<targer.length;i++) { Observer(targer[i]) } }else{ for(let key in targer){ // 响应式数据的函数 defineReactive(targer,key,targer[key]) } } } function updataView(){ console.log('视图更新了') } const data = { name:'海海', age:18, info:{ address:'广州' }, fava:[1,2,3,4,5] } Observer(data) </script>