关于简单的数据双向绑定原理,defineProperty 和Proxy演示

泄露秘密 提交于 2020-07-25 19:22:15

双向绑定,也就是说js中的数据传到页面,页面中的内容到js,实现同步更新,简单的演示可以直接复制下放HTML代码运行。

在这个例子中,我们使用defineProperty ,Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。详细信息可以自行查看MDN文档

简单来说,defineProperty 就是一个监听器,监听对象中某一个属性被访问和修改,在Vue2.0中就是采用defineProperty 

注意事项

  1. 在使用get函数监听属性的时候,不能直接监听当前属性,否则会出现死循环。所以在使用前我将对象进行浅拷贝的原因
  2. 每一个defineProperty只能对一个对象属性进行监听,所以你必须在使用之前就得知道属性的名字,但是很多时候属性是动态生成的,,所以就很麻烦。
  3. <!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>
    
        <h1 id="hname"></h1>
        <input type="text" id="inputname">
    </body>
    
    <script>
        let stu = {
            name: ""
        }
        let newstu = { ...stu };//浅拷贝
        //监听器
        Object.defineProperty(stu, "name", {
            get() {
                return newstu.name;
            },
            set(val) {
                if (val === newstu.name) return;
                newstu.name = val;
                doubleBind();
            }
        })
        //将数据传到页面中
        function doubleBind() {
            document.querySelector("#hname").innerHTML = stu.name;
            inputname.value = stu.name;//id可以直接使用
        }
        //输入框事件,将页面中数据返回
        inputname.oninput = function () {
            stu.name = inputname.value;
        }
        doubleBind()
        setTimeout(() => {
            stu.name = "Mary";
        }, 1000)
    </script>
    
    </html>

     

defineProperty的弊端很明显,在ES6中提出了Proxy, 在Vue3.0中也将使用Proxy代替defineProperty,在Proxy中,我们可以在监听整一个对象属性的变化。

<!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>

    <h1 id="hname"></h1>
    <input type="text" id="inputname">
</body>

<script>
    let stu = {
        name: "12354"
    }
    
    //监听器处理函数
   
    //监听器
    stu = new Proxy(stu, {
        get(target, prop) {
          
            return target[prop];
        },
        set(target, prop,val){
            if (val === target.prop) return;
            target[prop] = val;
            doubleBind();
        }
    });
    //将数据传到页面中
    function doubleBind() {       
        document.querySelector("#hname").innerHTML = stu['name'];
        inputname.value = stu['name'];//id可以直接使用
    }
    //输入框事件,将页面中数据返回
    inputname.oninput = function () {
        stu['name'] = inputname.value;
    }
    doubleBind()
    setTimeout(() => {
        stu['name'] = "Mary";
        console.log(stu);
    }, 1000)
</script>

</html>

 

 

对比两个例子,眼尖的friend会发现,第一个例子中我访问对象属性使用的是stu.name,而在第二个例子中使用的是stu['name']的方式。在《javascript高级程序设计》

引用类型的那一章提到:一般来说,访问对象属性时使用的都是点表示法,这也是很多面向对象语言中通用的语法。不过,

在 JavaScript 也可以使用方括号表示法来访问对象的属性。 除非必须使用变量来访问属性,否则我们建议使用点表示法。在我们第二个例子Proxy中,prop是一个变量,所以我们使用方括号。特别要注意, stu.namestu[name]是不一样的,当然如果有外部变量name=“name“,就一样了



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!