vue2.0与vue3.0 双向数据绑定原理 区别
用过vue的人都知道 vue2.x实现双向数据绑定的原理是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。
在MDN上对该方法的说明是:Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
它接收三个参数,要操作的对象,要定义或修改的对象属性名,属性描述符。重点就是最后的属性描述符。
属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。
这两种对象只能选择一种使用,不能混合两种描述符的属性同时使用。上面说的get和s et就是属于存取描述符对象的属性。
然后我们可以通过在存取描述符中的get和set方法内写入自定义的逻辑来实现对象获取属性和设置属性时的行为。
用代码演示vue2.x的原理
<!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> <div> <input type="text" id="input"> <span id="text"></span> </div> </body> </html> <script> var obj = {}; Object.defineProperty(obj, 'prop', { get: function () { return val; }, set: function (newVal) { val = newVal; document.getElementById('text').innerHTML = val; } }); document.addEventListener('keyup', function (e) { obj.prop = e.target.value; }); </script>
浏览器展示
Vue3.x是用ES6的语法 Proxy对象来实现的,这个玩意儿也可以实现数据的劫持
用代码演示vue3.x的原理
<!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> <div> <input type="text" id="input"> <span id="text"></span> </div> </body> </html> <script> var obj = {}; var obj1 = new Proxy(obj, { // target就是第一个参数obj, receive就是返回的obj(返回的proxy对象) get: function (target, key, receive) { // 返回该属性值 return target[key]; }, set: function (target, key, newVal, receive) { // 执行赋值操作 target[key] = newVal; document.getElementById('text').innerHTML = target[key]; } }) document.addEventListener('keyup', function (e) { obj1[0] = e.target.value; }); </script>
浏览器展示为
相比于vue2.x,使用proxy的优势如下
- 1 defineProperty只能监听某个属性,不能对全对象监听
- 2 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 3 可以监听数组,不用再去单独的对数组做特异性操作
- vue3.x可以检测到数组内部数据的变化