比较Vue2与Vue3的响应式

1 vue2

Vue2.0中使用ES5中的Object.defineProperty方法实现响应式数据
缺点
无法监测到对象属性的动态添加和删除
无法监测到数组的下标和length属性的变更
解决方案
Vue2.0提供Vue.set方法用于动态给对象添加属性
Vue2.0提供Vue.delete方法用于动态删除对象的属性
重写vue中数组的方法,用于监测数组的变更

  <body>
    <script>
      // vue会做一个数据劫持,,,监视数据的变化,一旦数据变化了,更新DOM
      const data = {
        name: 'zs',
        age: 18
      }
      for (let k in data) {
        let temp = data[k]
        Object.defineProperty(data, k, {
          get() {
            console.log(`我劫持了${k}的获取`)
            return temp
          },
          set(value) {
            console.log(`我劫持了${k}的设置,值${value}`)
            temp = value
          }
        })
      }
      // Object.defineProperty有缺点
      // 1. 无法监视到新增的属性的变更和删除
      // 2. 无法劫持到数组的下标和长度
    </script>
  </body>
  <body>
    <div id="app">
      <h1>vue的例子</h1>
      <p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
      <p>{{arr}}</p>
    </div>
    <script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
    <script>
      // vue中需要使用$set方法动态的增加一个响应式属性
      const vm = new Vue({
        el: '#app',
        data: {
          car: {
            brand: '奔驰',
            color: 'blue'
          },
          arr: ['张三', '李四']
        }
      })
    </script>
  </body>

2 vue3

通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等...
通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
Vue3.0中使用ES6中的proxy语法实现响应式数据
优点
可以检测到代理对象属性的动态添加和删除
可以监测到数组的下标和length属性的变更
缺点
ES6的proxy语法对于低版本浏览器不支持,IE11
Vue3.0会针对于IE11出一个特殊的版本用于支持ie11

  <body>
  <div></div>
  <script>
    const data = {
      name: 'zs',
      age: 18
    }
    // 能够监测到对象动态新增的属性以及删除的属性
    // proxy
    const proxyData = new Proxy(data, {
      get(target, name) {
        console.log(`检测到${name}的获取`)
        return target[name]
      },
      set(target, name, value) {
        console.log(`检测到${name}的设置,值为${value}`)
        target[name] = value
      },
      deleteProperty(target, key) {
        console.log(`监测到删除${key}`)
        return delete target[key]
      }
    })
  </script>
</body>
  <body>
  <div id="app">
    <h1>vue的例子</h1>
    <p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
    <p>{{arr}}</p>
  </div>
  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const App = {
      data() {
        return {
          car: {
            brand: '宝马',
            color: 'green'
          },
          arr: ['张三', '李四']
        }
      },
      methods: {
        fn() {
          this.car.brand = '奔驰'  //不再需要vue2中的$set方法就用代理更新
          // 会在DOM更新后才会执行回调函数
          nextTick(function () {
            // vue为了性能考虑,不会改变完数据就立即更新DOM
            console.log(document.querySelector('p').innerHTML)
          })
        }
      }
    }
    const vm = Vue.createApp(App).mount('#app')
  </script>
</body>
new Proxy(data, {
  // 拦截读取属性值
  get (target, prop) {
  	return Reflect.get(target, prop)
  },
  // 拦截设置属性值或添加新属性
  set (target, prop, value) {
  	return Reflect.set(target, prop, value)
  },
  // 拦截删除属性
  deleteProperty (target, prop) {
  	return Reflect.deleteProperty(target, prop)
  }
})

proxy.name = 'tom'   
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Proxy 与 Reflect</title>
</head>
<body>
  <script>
    
    const user = {
      name: "John",
      age: 12
    };

    /* 
    proxyUser是代理对象, user是被代理对象
    后面所有的操作都是通过代理对象来操作被代理对象内部属性
    */
    const proxyUser = new Proxy(user, {

      get(target, prop) {
        console.log('劫持get()', prop)
        return Reflect.get(target, prop)
      },

      set(target, prop, val) {
        console.log('劫持set()', prop, val)
        return Reflect.set(target, prop, val); // (2)
      },

      deleteProperty (target, prop) {
        console.log('劫持delete属性', prop)
        return Reflect.deleteProperty(target, prop)
      }
    });
    // 读取属性值
    console.log(proxyUser===user)
    console.log(proxyUser.name, proxyUser.age)
    // 设置属性值
    proxyUser.name = 'bob'
    proxyUser.age = 13
    console.log(user)
    // 添加属性
    proxyUser.sex = '男'
    console.log(user)
    // 删除属性
    delete proxyUser.sex
    console.log(user)
  </script>
</body>
</html>
posted @ 2021-01-14 16:54  sk-xm  阅读(685)  评论(0编辑  收藏  举报