zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    配置DNS域名解析服务器
    使用buildroot编译bind DNS服务器
    java值得注意的几个问题
    访问权限
    import static与import的区别
    八大排序算法
    移植DNS服务bind
    Sql存储过程中延迟执行
    【转】ado实体数据模型增删改查基本用法
    JS 拖动事件
  • 原文地址:https://www.cnblogs.com/fanlu/p/10801651.html
Copyright © 2011-2022 走看看