Vue2数据双向绑定原理
程序员文章站
2022-07-02 20:28:41
...
数据双向绑定原理
- 思路:Vue内部通过(数据劫持)Object.defineProperty方法劫持各个属性的setter,getter,结合发布者-订阅者模式的方式,当数据变化时触发相应监听回调通知视图更新。
let oldArrayPrototype=Array.prototype;//先拿到原来数组原型上的方法
let proto=Object.create(oldArrayPrototype);//克隆数组原型对象
['push','shift','unshift','pop','reverse','sort'].array.forEach(method => {
proto[method]=function(){//给克隆出来的对象重新写方法,不会影响数组原型
//函数劫持,把函数进行重写,但内部继续调用老的方法
updateView();//更新视图,切片编程
oldArrayPrototype[method].call(this,...arguments);
}
});
//把一个对象的每一属性都转化成可观测对象
function observer(target) {
if(typeof target !=='object'||target===null){//如果不是对象直接返回
return target;
}
if(Array.isArray(target)){
/* 拦截数组,给数组的方法进行了重写.如果target是数组,则让它的原型链可以找的到proto,即可实现调用数组方法时找到proto重写的数组方法proto[method] */
Object.setPrototypeof(target,proto);//ES6语法,如果不支持ES6语法,可以写个循环赋值给target
// target.__proto__=proto;
for(let i = 0; i< target.length ;i++){
observer(target[i]);
}
}else{
for (let key in target) {//对对象的劫持
defineRective(target,key,target[key]);//每个函数都有一个value属性,利用这个方法重新定义对象的属性和值
}
}
}
//使一个对象转化成可观测对象
function defineRective(target,key,value) {//静态属性target:全局唯一的Watcher
observer(value);/* 若当前value是对象,则继续拦截重新观察,变成被观察后的结果返回再赋值给里面,实现递归调用。但若数据层级较深,会出现递归使内存增大 */
object.defineProperty(target,key,{//get和set应当操作共同的值
get(){//get中会进行依赖收集,负责收集订阅者,然后当数据变化的时候后执行对应订阅者的更新函数。
return value;//获取时直接返回旧的值
},
set(newValue){
observer(newValue);//新赋的值也有可能是对象,重新观察
if(newValue!==value){//如果新的值不等于老的值那么更新视图和值
updateView();//数据变化通知所有订阅者
value=newValue;
}
}
})
}
//缺点1:如果属性不存在,新增的属性不会是响应式的(因为只循环当前存在的属性)
function updateView() {
console.log('更新视图');
}
//使用Object.defineProperty 就是可以重新定义属性,给属性增加getter和setter
/* let data={name:'hhh',age:{n:100}};
observer{data};//写个方法观察数据,观察完之后去更改数据
data.name='jw';
data.age.n=200;
data.age={n:200};//给age新赋的对象没有被set和get,不会更新
data.age.n=300; */
let data={name:'hhh',age:[1,2,3]}
observer(data);
data.age.push(4);/* 需要对数组上的方法进行重写 push shift unshift pop push reverse sort,不能直接更改Array.prototype.push=function () {……},因为直接把原型上的方法重写会导致未被观察的数据也会被重写,应该新创建一个方法,让被观察后的对象属性值为数组的话能找到该方法 */
- vue2双向绑定缺点:
- 2.0 默认会递归
- 数组改变length 是无效的
- 对象不存在的属性不能被拦截
上一篇: Windows10中快捷键的使用