• Object.defineProperty和Proxy的区别和优势


    // Object.defineProperty的第一个缺陷,无法监听数组变化 如这种数组改变方式 list[0] = xx; 对象的话是 var obj = {a: 1} obj.b = 2; Vue.set() / this.$set()
    /* 以下八种方法Vue是可以检测到数组变化的进行了数组方法重载
    push()
    pop() // 删除并返回数组的最后一个元素
    shift() // 把数组的第一个元素从其中删除,并返回第一个元素的值
    unshift() // 向数组的开头添加一个或更多元素,并返回新的长度
    splice()
    sort()
    reverse()
    */
    // 这是将要被劫持的对象
    const obj = {
        name: 'bob',
        age: 25
    };
    
    function test(age) {
        if (age === 25) {
            console.log('这是我的年龄');
        } else if (age > 25) {
            console.log('油腻大叔');
        } else {
            console.log('风花雪月的日子一去不复返了');
        }
    }
    // 遍历对象,对其属性值进行劫持
    Object.keys(obj).forEach(function(key) {
        // 语法 Object.defineProperty(obj, prop, descriptor) obj 要定义属性的对象。prop 要定义或修改的属性的名称或 Symbol, descriptor要定义或修改的属性描述符。
        /*描述符默认值汇总
          拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
          属性值和函数的键 value、get 和 set 字段的默认值为 undefined
        */
        Object.defineProperty(obj, key, {
            enumerable: true, // 当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false
            configurable: true, // 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除,默认false。
            get: function() {
                console.log('get');
            },
            set: function(newVal) {
                // 当属性值发生变化时我们可以进行额外操作
                console.log(`新值${newVal}`);
                // document.getElementById('input').value = newVal; // 例如双向绑定原理 输入框的 e.target.value;
                test(newVal)
            }
        })
    })
    obj.age = 26;
    console.log(obj.age, 'obj.age')
    /* 输出结果
    新值26
    油腻大叔
    get
    undefined "obj.age"
    */
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title></title>
        </head>
        <body>
            <div>es6</div>
            <div id="app">
                <input type="text" id="input" />
                <div>输入框的值: <span id="title"></span></div>
                <button type="button" name="button" id="btn">添加到list</button>
                <ul id="list"></ul>
            </div>
            <script type="text/javascript">
                /*
                  Object.defineProperty() 的问题主要有三个
                  不能监听数组的变化
                  必须遍历对象的每个属性
                  必须深层遍历嵌套的对象
                */
               // Proxy语法糖 优势 解决了vue2.0 Object.defineProperty 没解决的几个问题 Proxy 的第二个参数可以有 13 种拦截方法
               // target:[目标值], key:[目标的key值], value:[要改变的值], receiver:[改版前的原始值]
               /*
                 针对对象:针对整个对象,而不是对象的某个属性
                 支持数组:不需要对数组的方法进行重载,省去了众多 hack
                 嵌套支持(本质也是不支持嵌套的): get 里面递归调用 Proxy 并返回
               */
              // 劣势:Proxy 的兼容性不如 Object.defineProperty() 不能使用 polyfill 来处理兼容性
               // var proxy = new Proxy(target, handler);
                const obj = {};
                const inp = document.getElementById("input");
                const title = document.getElementById("title");
                // 监听对象
                // Reflect.get():获取对象身上某个属性的值,类似于 target[name]。
                // Reflect.set():将值分配给属性的函数,返回一个Boolean,如果更新成功,则返回true。
                const newObj = new Proxy(obj, {
                    get: function(target, key, receiver) {
                        console.log(`getting ${key}!`);
                        return Reflect.get(target, key, receiver); // Reflect.get 和 Reflect.set 可以理解为类继承里的 super,即调用原来的方法
                    },
                    set: function(target, key, value, receiver) {
                        console.log(target, key, value, receiver, '对象劫持');
                        if (key === "text") {
                            inp.value = value;
                            title.innerHTML = value;
                        }
                        return Reflect.set(target, key, value, receiver);
                    }
                });
                inp.addEventListener("keyup", function(e) {
                    newObj.text = e.target.value;
                });
                // 渲染list列表
                const render = {
                    // 初始化
                    init: function(arr) {
                        // document.createDocumentFragment 创建一个新的空白的文档片段因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。
                        // 因此,使用文档片段通常会带来更好的性能
                        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);
                    },
                    addItem: function(val) {
                        const li = document.createElement("li");
                        li.textContent = val;
                        list.appendChild(li);
                    }
                };
                // 监听数组
                const arr = [];
                const newArr = new Proxy(arr, {
                    get: function(target, key, receiver) {
                        return Reflect.get(target, key, receiver);
                    },
                    set: function(target, key, value, receiver) {
                        console.log(target, key, value, receiver,'数组的劫持响应');
                        if (key !== "length") {
                            render.addItem(value);
                        }
                        return Reflect.set(target, key, value, receiver);
                    }
                });
                // 初始化
                window.onload = function() {
                    render.init(arr);
                };
                btn.addEventListener("click", function() {
                    newArr.push(parseInt(newObj.text));
                });
            </script>
        </body>
    </html>
  • 相关阅读:
    QGIS 编译
    Ubuntu: 无法使用su命令
    win7 与 Ubuntu 16.04 文件传送
    OSGEarth编译
    GADL配置编译
    C++ 类对象和 指针的区别
    C++ Primer Plus 第六版笔记
    Windows下使用doxygen阅读和分析C/C++代码
    _MSC_VER详细介绍
    LUA学习之一 初次接触
  • 原文地址:https://www.cnblogs.com/lhl66/p/13636108.html
Copyright © 2020-2023  润新知