2、带你一步步实现vue3源码之reactive

181 阅读2分钟

Reactive

何为响应式对象,在我看来就是一个可以进行拦截的对象,vue2采用的是Object.definePropertyvue3采用的是Proxy,至于vue3为什么要采用proxy这里我们不做过多解释,大家可自行了解。

单测

下面,跟着下面的单测一起来了解下reactive的具体功能点。

// src/reactivity/test/reactive.spec.ts

import {reactive} from '../reactive'
describe("reactive", () => {
  it("happy path", () => {
    const origin = {
      foo: 1
    }
    const obj = reactive(origin)
    expect(obj).not.toBe(origin)
    expect(obj.foo).toBe(1)
  })
})

在vue3里,直接通过一个reactive(obj)函数创建一个proxy对象,返回的对象属性和值都和obj保持一直,但他们属于不同的两个对象。

代码实现

根据上面单测的功能点,我们开始一步步的来实现我们的reactive函数。

创建./src/reactivity/reative.ts文件

1、导出一个reactive函数,接收用户传入的object数据。

export function reactive (raw) {
  // write at this
}

2、返回一个Proxy实例

Proxy接收2个参数,第一个是需要劫持的object,第二个参数是一个options,这里我们只用设置getset

export function reactive (raw) {
  return new Proxy(raw, {
    get (target, key) {},
    set (target, key, value) {}
  })
}

3、处理get请求

当获取这个响应式对象的某个属性时调用,target就是获取的objectkey就是获取的对象属性名称。

例如:obj.name,target代表obj,而key则代表name

提示:这里的Reflect.get(target, key)其实就是获取target对象的key属性的值,最后在get中返回这个值即可。

get (target, key) {
  const res = Reflect.get(target, key)
  return res
}

4、处理set赋值

当执行了赋值操作时会调用set方法,target是操作的对象,key是操作对象的属性名称,value是赋值。

Reflect.set(target, key, value)即是给target对象的key属性赋值value,该执行结果是boolean,即代表赋值成功与否。

set (target, key, value) {
  const res = Reflect.set(target, key, value)
  return res
}

到这里,我们就成功创建了一个响应式对象,给这个响应式对象添加了set,和get操作。

代码报错

03.png

写完后发现我们的代码一直报错,可我们写的代码也没问题,这是因为typescript配置问题,在tsconfig.json中加上"lib": ["DOM", "ES6"]

测试结果

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.889 s, estimated 1 s
Ran all test suites.
Done in 2.25s.

执行yarn test或者yarn test reactive,我们的测试没有报错,就说明我们的功能已经完成,如果有报错,请参考上面的步骤仔细检查。

总结

最后我们再一起来回顾一下这一节我们实现的代码及功能,在reactive.ts中我们导出了reactive函数,自身接收一个obj作为参数,并基于obj返回一个proxy对象,我们还简单的处理了一下proxygetset请求,后面我们将会对这个proxy对象进行完善,真正达到响应式。

下一节,我们将一起了解vue3的effect