vue之雙向綁定

Vue的一大核心是雙向綁定,在2.0中採用數據劫持,用Object.defineProperty實現,但做者已聲明在3.0中會採用proxy實現
 
Object.defineProperty是什麼?proxy是什麼?爲何要換呢?咱們來探討下
 
 
 
Object.defineProperty
 
是js中一個高級方法,理解它有助於咱們更好地理解面向對象及理解vue運行原理
 

定義:

Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象 vue

 

語法:

Object.defineProperty(obj, prop, descriptor)

參數:

  • obj     要在其上定義屬性的對象。
  • prop     要定義或修改的屬性的名稱。
  • descriptor 將被定義或修改的屬性描述符。

返回值:

被傳遞給函數的對象數組

 

詳細語法介紹請參考MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertyapp

示例:

本身簡單寫了個示例,方便理解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方法,進而能夠派發出事件,通知監聽者。spa

缺點:

  1. 沒法監聽數組變化
  2. 只能劫持對象的屬性(因此須要深度遍歷)

Proxy雙向綁定

Proxy在ES2015規範中被正式發佈,它在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫,咱們能夠這樣認爲,Proxy是Object.defineProperty的全方位增強版code

  • 能夠直接監聽對象而非屬性
  • 能夠直接監聽數組的變化
  • 有多達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>

攔截數組:blog

    <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>
相關文章
相關標籤/搜索