1. 先来回顾一下Vue2.0的响应式原理
- 通过 Object.defineProperty() 实现数据劫持
存在的问题
- 针对对象:新增属性,删除属性,界面不更新
- 针对数组:通过下标修改数组,界面不会自动更新
<!DOCTYPE html> <html> <head> <title>模拟vue2.0</title> </head> <body> <input type="text" id="username"> <br> 显示值:<span id="uName"></span> <script> var obj = {}; // 模拟双向数据绑定 //Object.defineProperty(obj, prop, descriptor) //直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。 //obj 要在其上定义属性的对象。 //prop 要定义或修改的属性的名称。 //descriptor 将被定义或修改的属性描述符。 Object.defineProperty(obj,"username",{ // Value:"Jack", get:function(){ console.log("取值"); }, set:function(val){ console.log("设置值"); document.getElementById("uName").innerText=val; } }); document.getElementById("username").addEventListener("keyup",function(){ obj.username= event.target.value; }) //在控制台中输入obj.username会自动触发get方法,输入obj.username="aaa"会自动触发set方法 //此时并没有用事件进行监听,所以修改监听事件里的代码 </script> </body> </html>
2. Vue3.0原理实现 —— Proxy()
- 引用数据类型的增删改查统统在行,非常强大
<!DOCTYPE html> <html> <head> <title>vue3响应式</title> </head> <body> <script> // type="text/javascript" let obj = { name: '小明', age: 18 } // 1. window内置的 // window.Proxy() => 代理 // obj为源数据 const p = new Proxy(obj, { // 这里虽然也是get set 但是要比Object.defin()要聪明一些 get(target, propName){ // target 源数据 // b具体属性 // console.log("读取P的属性") // a, b console.log(`读取P的${propName}属性`) // return target[propName] return Reflect.get(target, propName) }, // 修改+新增都可以捕获 set(target, propName, value){ // console.log("修改了P的属性") console.log(`修改了P的${propName}属性,值为${value}`) // 写到这里 还不是响应式 要去修改obj的值 // target[propName] = value return Reflect.set(target, propName, value) }, // 加一个删除 deleteProperty(target, propName){ console.log(`删除了P的${propName}属性`) // return delete target[propName] return Reflect.deleteProperty(target, propName) }, }) </script> </body> </html>
3. 重点说明 —— Reflect
3.1 Reflect 是用来做什么的?
动态对被代理对象的相应属性进行特定的操作(ES6新增)
看到上面的代码,你会发现每行Reflect代码上面都注释了一行,实际上不用它,用它上面的代码也可以实现响应式
但是Vue3.0 却用的是 Reflect,还是有些深意的
3.2 为什么要用Reflect ?
大家可以自行百度,我这里简单说一下
简单来说,主要是为了减少源码中的 try catch,如果不使用 Reflect,整个框架需要有大量的 try catch,才能保证在出错的情况下顺利运行,但是源码就会不好维护,看起来不雅观
使用Reflect,即使代码出错,可以在抛出错误的同时,让代码正常运行,保证框架的健壮性!