欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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双向绑定缺点:
    1. 2.0 默认会递归
    2. 数组改变length 是无效的
    3. 对象不存在的属性不能被拦截
相关标签: vue