vue2的实现(5)之对象劫持的一些细节处理二

363 阅读3分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

vue2的实现(5)之对象劫持的一些细节处理二

回顾

  • 上次内容我们处理了一个问题,假如用户重新给数据赋值为对象类型的数据,那我们就观测不到这个数据了。因为在属性的set方法中,我们可以劫持到用户设置数据的操作,所以我们需要在这里对用户设置的值,再做一次观测,我们只要observe(newValue)就可以了,下面是rewrite-vue/src/observe/index.js中的代码。

  • rewrite-vue/src/observe/index.js

    class Observe {
      consturctor(data){
        this.walk(data)
      }
    
      walk(data){
        Object.keys(data).forEach(key => defineReactive(data, key, data[key]))
      }
    }
    
    export function defineReactive(target, key, value){
      Object.defineProperty(target, key, {
        get(){
          console.log('劫持用户的取值操作,get');
          return value
        },
        set(newValue){
          if(newValue !== value){
            console.log('劫持用户的设置操作,set');
            observe(newValue)
            value = newValue
          }
        }
      })
    }
    
    
    export function observe(data){
      if(typeof data !== 'object' || data === null){
        return 
      }
      return new Observe(data)
    }
    

观测不到嵌套深层的对象

  • 我们用下面的代码测试一下,在浏览器打开rewrite-vue/dist/index.html

  • rewrite-vue/dist/index.html

      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Vue2</title>
      </head>
      <body>
      <script src="./vue.js"></script>
      <script>
          const vm = new Vue({
            data:{
                name:'vue2',
                age: {
                  num:666,
                  key:'age'
                }
              }
          })
    
    
    
          console.log(vm._data.age.key);
          vm._data.age.num = 999
      </script>
      </body>
      </html>
    
  • 下面的图片是输出结果,我们可以看到console.log(vm._data.age.key)只打印了一次get的输出。vm._data.age.num = 999只打印了一次get的输出。

  • 按理说,我们访问vm._data.age.key,在访问age时打印一次get,在访问key的时候也应该打印一次get。在设置vm._data.age.num = 999的时候,访问age属性时打印一次get输出,设置num属性时要打印一次set的输出。

    2022-01-29-1.png

  • 所以说,我们在defineReactive中需要对每个对象的属性再次进行观测,因为有的属性有可能是对象类型的数据,对于对象类型的数据我们需要进行递归观测,这样在用户进行获取和设置的时候,我们才可以劫持到用户的操作。

  • rewrite-vue/src/observe/index.js

    class Observe {
      consturctor(data){
        this.walk(data)
      }
    
      walk(data){
        Object.keys(data).forEach(key => defineReactive(data, key, data[key]))
      }
    }
    
    export function defineReactive(target, key, value){
      observe(value)
      Object.defineProperty(target, key, {
        get(){
          console.log('劫持用户的取值操作,get');
          return value
        },
        set(newValue){
          if(newValue !== value){
            console.log('劫持用户的设置操作,set');
            observe(newValue)
            value = newValue
          }
        }
      })
    }
    
    
    export function observe(data){
      if(typeof data !== 'object' || data === null){
        return 
      }
      return new Observe(data)
    }
    

测试

  • rewrite-vue/dist/index.html里面的代码还是上面的测试用例,我们再次在浏览器中打开rewrite-vue/dist/index.html可以看到。

  • 从下面的图可以看出我们的打印已经生效了,而且打印的内容也和我们所设想的一样,证明我们的修改已经生效了。

    2022-01-29-2.png 今天是更文第十二天加油~ 看到这里兄弟帮忙点个赞吧

往期精彩

vue2的实现(4)之对象劫持的一些细节处理一

vue2的实现(3)之对象的劫持

vue2的实现(2)之初始化数据data

vue2的实现(1)之搭建rollup打包环境

手撕koa,从零掌握koa的实现原理(1)

手撕koa,从零掌握koa的实现原理(2)

手撕koa,从零掌握koa的实现原理(3)

手撕koa,从零掌握koa的实现原理(4)

手撕koa,从零掌握koa的实现原理(5)

手撕koa,从零掌握koa的实现原理(6)

手撕koa,从零掌握koa的实现原理(7)