vue2源码-二、对象响应式原理

对象响应式原理

  • 初始化操作,扩展init方法:

    // index.js
    function Vue(options) {
      this._init(options)
    }
    initMixin(Vue) // 扩展了init方法
    export default Vue
    

    initMinin方法中,扩展了init方法。

    以下获用户的option

    // init.js
    import { initState } from './state.js'
    
    // 就是给Vue增加init方法的
    export function initMixin(Vue) {
      // 初始化操作
      Vue.prototype._init = function (options) {
        // vue vm.$options就是获取用户的配置
        // 使用vue的时候$是vue定义的,而且再实例上
        const vm = this
        vm.$options = options // 将用户的选项挂载到实例上
    
        // 初始化状态
        initState(vm)
      }
    }
    
  • 核心模块observe:数据监测

    data数据的响应式原理:通过Object.definProperty重写data上的所有属性。

    调用的initState方法,这个方法需要对数据进行劫持。

    import { observe } from './observe/index'
    
    // 主函数
    // 1. 封装主函数,如果存在data属性,则进行初始化数据
    export function initState(vm) {
      const opts = vm.$options
      // options不是空
      if (opts.data) {
        initData(vm)
      }
    }
    // vm._data.name 变成vm.name 代理
    function proxy(vm, target, key) {
      Object.defineProperty(vm, key, {
        get() {
          return vm[target][key]
        },
        set(newValue) {
          vm[target][key] = newValue
        },
      })
    }
    
    // 2.初始化数据
    function initData(vm) {
      let data = vm.$options.data // 可能是函数和对象
      // data可能是函数也可能是对象,函数需要进行this绑定。
      data = typeof data === 'function' ? data.call(vm) : data // data是用户返回的对象
      vm._data = data // 将返回的对象放到_data
      // 对数组进行劫持vue2里采用一个api defineProperty
      // 3.后面会提及
      observe(data)
      // 将vm._data用vm来代理就可以了
      for (let key in data) {
        proxy(vm, '_data', key)
      }
    }
    

    Obsever类:对对象进行观测。

    observe方法:

    export function observe(data) {
      // 对这个对象进行劫持
      if (typeof data !== "object" || data === null) {
        return; // 只对对象进行劫持
      }
      // 如果一个对象被劫持过了,那就不需要在劫持了(判断一个对象是否被劫持过,可以添加一个实例,用实例来判断是否被劫持过)
      return new Observe(data);
    }
    

    这个方法返回了一个输入数据的观测对象。

    那返回一个什么样的对象呢?

    // 循环对象进行一次劫持
    class Observer{
     	constructor(value){
            this.walk()
        }   
        walk(data) {
        // 重新定义属性
        Object.keys(data).forEach((key) => defineReactive(data, key, 	data[key]))
    	}
    }
    // 属性劫持
    // 对对象target,定义属性key,值为value
    // 使用Object.definProperty重新定义data的属性
    export function defineReactive(target, key, value) {
      observe(value) // 递归对所有的属性进行劫持
      Object.defineProperty(target, key, {
        // 用户取值
        get() {
          console.log('用户设置值00')
          return value
        },
        // 用户设置值了
        set(newValue) {
          console.log('用户取值了')
          if (newValue === value) return
          // 递归,设置了对象
          observe(newValue)
          value = newValue
        },
      })
    }
    
posted @   楸枰~  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示