vue之双向绑定

Vue的一大核心是双向绑定,在2.0中采用数据劫持,用Object.defineProperty实现,但作者已声明在3.0中会采用proxy实现
 
Object.defineProperty是什么?proxy是什么?为什么要换呢?我们来探讨下
 
 
 
Object.defineProperty
 
是js中一个高级方法,理解它有助于我们更好地理解面向对象及理解vue运行原理
 

定义:

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象 

 

语法:

Object.defineProperty(obj, prop, descriptor)

参数:

  • obj     要在其上定义属性的对象。
  • prop     要定义或修改的属性的名称。
  • descriptor 将被定义或修改的属性描述符。

返回值:

被传递给函数的对象

 

详细语法介绍请参考MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

示例:

自己简单写了个示例,方便理解Object.defineProperty

     var data = {
            name: "jade",
            age: 18, 
        }
        Object.keys(data).forEach(key=>{
            var vl = data[key];
            Object.defineProperty(data,key,{
                get(){ 
                    console.log(key + "...get..."); 
                    return vl;
                },
                set(value){ 
                    console.log(key + "...set... value is " + value);
                    vl = value;
                }
            });
        })

        console.log("age:"+data.age);   
        data.age = 20;
        data.name = "jake";
        console.log("age:"+data.age); 

在读取属性或者给属性赋值时,会进入get和set方法,进而可以派发出事件,通知监听者。

缺点:

  1. 无法监听数组变化
  2. 只能劫持对象的属性(所以需要深度遍历)

Proxy

Proxy在ES2015规范中被正式发布,它在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,我们可以这样认为,Proxy是Object.defineProperty的全方位加强版

  • 可以直接监听对象而非属性
  • 可以直接监听数组的变化
  • 有多达13种拦截方法
  • 返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改。
  • 劣势就是兼容性问题,而且无法用polyfill磨平,因此Vue的作者才声明需要等到下个大版本(3.0)才能用Proxy重写。

示例:

拦截对象:

   <input id="input" type="text"/>
    <p id="p"></p>

    <script> 
        const input = document.getElementById('input');
        const p = document.getElementById('p');
        const obj = {};

        const newObj = new Proxy(obj, {
        get: function(target, key, receiver) {
            console.log(`getting ${key}!`);
            return Reflect.get(target, key, receiver);
        },
        set: function(target, key, value, receiver) {
            console.log(target, key, value, receiver);
            if (key === 'text') {
                input.value = value;
                p.innerHTML = value;
            }
            return Reflect.set(target, key, value, receiver);
        },
        });

        input.addEventListener('keyup', function(e) {
            newObj.text = e.target.value;
        });
    </script>

拦截数组:

    <ul id="list">  </ul>
    <input id="btn" value="test" type="button"/> 

    <script> 
        const list = document.getElementById('list');
        const btn = document.getElementById('btn');

        // 渲染列表
        const Render = {
        // 初始化
        init: function(arr) {
            const fragment = document.createDocumentFragment();
            for (let i = 0; i < arr.length; i++) {
                const li = document.createElement('li');
                li.textContent = arr[i];
                fragment.appendChild(li);
            }
            list.appendChild(fragment);
        },
        // 我们只考虑了增加的情况,仅作为示例
        change: function(val) {
            const li = document.createElement('li');
            li.textContent = val;
            list.appendChild(li);
        },
        };

        // 初始数组
        const arr = [1, 2, 3, 4];

        // 监听数组
        const newArr = new Proxy(arr, {
        get: function(target, key, receiver) {
            console.log(key);
            return Reflect.get(target, key, receiver);
        },
        set: function(target, key, value, receiver) {
            console.log(target, key, value, receiver);
            if (key !== 'length') {
            Render.change(value);
            }
            return Reflect.set(target, key, value, receiver);
        },
        });

        // 初始化
        window.onload = function() {
            Render.init(arr);
        }

        // push数字
        btn.addEventListener('click', function() {
        newArr.push(6);
        }); 

    </script>

 

posted @ 2019-05-02 09:36  jadefan  阅读(330)  评论(0编辑  收藏  举报