美文网首页ES6
ES6基本的语法(六) 实现双向绑定(ES5 写法)

ES6基本的语法(六) 实现双向绑定(ES5 写法)

作者: StevenTang | 来源:发表于2021-02-05 20:27 被阅读0次

    什么是双向绑定

    首先来说一下单向绑定,单向绑定就是把 Model 绑定到 View,当我们用 JS 代码更新 Model 时,View 就会自动更新。

    有单向绑定,就有双向绑定。如果用户更新了 View,Model 的数据也自动被更新了,这种情况就是双向绑定。

    object.defineProperty

    Object.defineProperty 是 ES5 中双向绑定的方法,下面开始介绍它的语法

    
    Object.defineProperty(obj, prop, descriptor);
    
    // Object.defineProperty(对象, 属性, 描述符)
    
    /* descriptor 对象属性的详细介绍 */
    /* 描述符 */
    
    value: ""  // 属性值 默认 ''
    weitable: true // 是否可写 默认值 false
    configurable: true //是否可配置 默认值 false
    enumerable: true // 是否可枚举 默认值 false
    
    
    /* 存取描述符 */
    
    set: function(){} // 属性访问器 进行写操作时调用该方法
    get: function(){} // 属性访问器 进行读操作时调用该方法
    
    

    描述符介绍

    我们在正常声明一个对象,都是可写,可配置,可枚举的。例如:

    
    let a = {
        name:'ccc'
    }
    
    a.name = "xxx" // weitable可写
    
    for(let i in a){
        console.log(i) //  输出 name 说明 enumerable 可枚举
    }
    
    delete a.name // 返回 true configurable 可配置
    
    

    使用 Object.defineProperty

    var a = {
    
    }
    
    Object.defineProperty(a,"name",{
        value: 'ccc',
    })
    
    a.name = "xxx"; // a.name 返回的还是 ccc
    delete a.name  // 返回 false
    for(var i in a){
        console.log(i) //返回 undefined
    }
    

    因为我通过 Object.defineProperty 设置的属性和属性值,后面的 weitable(写入)、configurable(配置)、enumerable(枚举) 都是默认值 false,所以不可写入,不可配置,不可枚举的。

    var a = {
    
    }
    
    Object.defineProperty(a,"name",{
        value: 'ccc',
        weitable: true
        configurable: true,
        enumerable: true
    })
    
    a.name = "xxx"; // a.name 返回 xxx
    delete a.name  // 返回 true
    for(var i in a){
        console.log(i) //返回 name
    }
    

    在设置 weitable(写入)、configurable(配置)、enumerable(枚举)这三个属性为 true 之后,就可以进行写入、配置、枚举操作。

    存取描述符

    我们下一下面的例子

    var a = {
    
    }
    
    Object.defineProperty(a,"name",{
        // 在设置 get 和 set 之后  value weitable 这两个属性就不能设置了
        // 在设置 get 和 set 之后  value weitable 不能共存
        configurable: true,
        enumerable: true,
        get: function (){
            console.log('执行get了');
        },
        set: function(){
            console.log('执行set了');
        }
    })
    
    a.name = "ccc";         // 输出 执行 set 了
    console.log(a.name);    // 输出 执行 get 了
    
    

    在上面代码中 a.name 被赋值 ccc,被 set 方法监听到执行 console.log('执行get了')。之后又访问 a.name 被 set 方法监听到执行 console.log('执行set了')

    
    var val;
    var a = {
    
    }
    
    Object.defineProperty(a,"name",{
        // 在设置 get 和 set 之后  value weitable 这两个属性就不能设置了
        // 在设置 get 和 set 之后  value weitable 不能共存
        configurable: true,
        enumerable: true,
        get: function (){
            console.log('执行get了');
            return val;
        },
        set: function(newVal){
          console.log('执行set了');
          val = newVal;
          console.log(val);
        }
    })
    
    a.name = "ccc";         // 输出 执行 set 了 并且执行 set 里面 console.log(val) 是 ccc;
    console.log(a.name);    // 输出 执行 get 了 打印 a.name 是 ccc
    
    

    简单的模拟一下双向绑定

    VUE2.0 双向数据绑定核心功能由 Observe、Compile、Watcher 三部分实现。其中 Observer 的部分功能由 Object.defineProperty 实现。(Observer 监测数据变化进行相应回调)。

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
        </head>
        <body>
            <input type="text" id='inputDemo'/> 
            <div id="txt"></div>
        </body>
        <script>
            var data = {
                value: 'ccc',
                name:{
                    nameData: "ttt"
                }
            }
            inputDemo.oninput = function(){
                data.name.nameData = this.value;
            }
            function upData (){
                txt.innerText = data.name.nameData;
            }
    
            upData();
    
            // 监控对象的某个属性是否发生改变
            function Observer (obj) {
                // 判断 obj 是否存在或类型不是对象 如果是直接返回 obj
                if(!obj || typeof obj != 'object') return obj;
    
                // 通过 keys 拿到 obj 的属性,之后在循环一个一个拿出来
                Object.keys(obj).forEach(function(ele){
                    // 执行 defineReactive(监听的对象, 监听对象的属性, 属性值)
                    defineReactive(obj,ele,obj[ele]);
                })
            }
            function defineReactive (obj,ele,value) {
                // 执行递归 value 里面还有没有深层的对象
                Observer(value);
                // 开始监听
                Object.defineProperty(obj,ele,{
                    get(){
                        console.log("执行了get")
                        return value;
                    },
                    set(newVal){
                        console.log("执行了set");
                        if(newVal == value) return
                        value = newVal;
                        upData();
                    }
                });
            }
            // 调用监听的方法
            Observer(data);
    
            data.value = 'xxx';
    
        </script>
    </html>
    
    

    通过这种方式写就可以实现 input 和 div 实现一个双向绑定。

    数组双向绑定

    Object.defineProper 不支持数组的监听,可以用 array.prototype 原型对象

    var arr = [];
    var push = Array.prototype.push
    function upData () {
        console.log('数组更新了')
    }
    
    var arrFun = ["pop","shift","unshift","splice ","splice", 'push']
    
    Object.defineProperty(Array.prototype, arrFun[5], {
        value: (function(){
            return function (){
                push.apply(arr, [].slice.call(arguments));
            }
        })()
    });
    
    arr[arrFun[5]](1,2);
    

    Object.defineProperty 除了支持监听数组之外,还对 Observer 之后新增的对象也不支持监听

    var data = {
        value: 'ccc',
        name:{
            nameData: "ttt"
        }
    }
    
    // 监控对象的某个属性是否发生改变
    function Observer (obj) {
        // ...
    }
    function defineReactive (obj,ele,value) {
        // ...
    }
    // 调用监听的方法
    Observer(data);
    
    data.a = 10; // Object.defineProperty 对这个属性 不支持监听
    // 因为在 Observer() 之后
    
    

    相关文章

      网友评论

        本文标题:ES6基本的语法(六) 实现双向绑定(ES5 写法)

        本文链接:https://www.haomeiwen.com/subject/nkvgtltx.html