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

313 阅读2分钟

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

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

回顾

  • 上次内容我们介绍了rewrite-vue/src/state.js,这个文件中主要做的就是对数据状态的初始化,下面是这个文件夹中的代码,我们拿到data后,接下来就到了对数据的劫持操作了。
  • rewrite-vue/src/state.js
    export function initState(vm){
      const opts = vm.options
      if(opts.data){
        initData(vm)
      }
    }
    
    function initData(vm){
      let data = vm.$options.data
      data = typeof data === 'function' ? data.call(vm) : data
      vm._data = data
    
      console.log(data)
    }
    

实现对象的劫持

  • 我们接着完成initData的方法,我们拿到用户传入的data数据之后,需要劫持对象属性的get set,通过observe方法来观测数据.
  • rewrite-vue/src/state.js
    import {observe} from './observe'
    export function initState(vm){
      const opts = vm.options
      if(opts.data){
        initData(vm)
      }
    }
    
    function initData(vm){
      let data = vm.$options.data
      data = typeof data === 'function' ? data.call(vm) : data
      vm._data = data
    
      observe(data)
    }
    
  • observe是一个独立的模块,我们需要拆分出去,新建rewrite-vue/src/observe文件夹.
  • 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');
            value = newValue
          }
        }
      })
    }
    
    
    export function observe(data){
      if(typeof data !== 'object' || data === null){
        return 
      }
      return new Observe(data)
    }
    
  • observe方法,主要是对对象类型的数据做劫持,返回一个Observe的实例,把数据传进去,consturctor中默认会调用walk方法,walk方法的作用是循环遍历对象,调用defineReactive方法,传入三个参数,target是要劫持的目标对象,key要劫持的属性,value劫持的属性对应的值.因为defineReactive方法需要暴露出去,所以这个方法,拆出来写,不写在Observe类中.
  • defineReactive方法的作用是劫持属性的get set 在用户获取值,设置值的时候我们可以拦截到用户的操作.

测试

在上面的代码rewrite-vue/src/observe/index.js中,我们在get set 中做了打印操作,可以来测试一下我们的代码.

  • 命令行输入npm run dev,打包文件到dist目录下

  • 在浏览器打开dist/index.html

  • 打开浏览器控制台,在控制台获取或者设置我们传入的data数据

  • 由于我们在src/state.jsinitData方法中给vm._data赋值为我们传入的data,也就是劫持过的data,我们可以直接通过vm._data去访问数据,vm就是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:3
          }
        })
      </script>
    </body>
    </html>
    
  • 从下面的图可以看出我们的打印已经生效了,证明我们已经拦截到了对象的获取与设置

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

往期精彩

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)