关于简单的数据双向绑定原理,defineProperty 和Proxy演示
双向绑定,也就是说js中的数据传到页面,页面中的内容到js,实现同步更新,简单的演示可以直接复制下放HTML代码运行。
在这个例子中,我们使用defineProperty ,Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。详细信息可以自行查看MDN文档。
简单来说,defineProperty 就是一个监听器,监听对象中某一个属性被访问和修改,在Vue2.0中就是采用defineProperty
注意事项
- 在使用get函数监听属性的时候,不能直接监听当前属性,否则会出现死循环。所以在使用前我将对象进行浅拷贝的原因
- 每一个defineProperty只能对一个对象属性进行监听,所以你必须在使用之前就得知道属性的名字,但是很多时候属性是动态生成的,,所以就很麻烦。
-
<!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高级程序设计》
引用类型的那一章提到:一般来说,访问对象属性时使用的都是点表示法,这也是很多面向对象语言中通用的语法。不过,