Vue.observable的理解

简介: Vue.observable的理解

 

一、Observable 是什么

Observable 翻译过来我们可以理解成可观察的

先来看其在Vue中的定义

Vue.observable,让一个对象变成响应式数据。Vue 内部会用它来处理 data 函数返回的对象

返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器


Vue.observable({ count : 1})


其作用等同于

new vue({ count : 1})


Vue 2.x 中,被传入的对象会直接被 Vue.observable 变更,它和被返回的对象是同一个对象

Vue 3.x 中,则会返回一个可响应的代理,而对源对象直接进行变更仍然是不可响应的


二、使用场景

在非父子组件通信时,可以使用通常的bus或者使用vuex,但是实现的功能不是太复杂,而使用上面两个又有点繁琐。这时,observable就是一个很好的选择


创建一个js文件

// 引入vue
import Vue from 'vue
// 创建state对象,使用observable让state对象可响应
export let state = Vue.observable({
  name: '张三',
  'age': 38
})
// 创建对应的方法
export let mutations = {
   changeName(name) {
     state.name = name
   },
   setAge(age) {
     state.age = age
   }
 }


.vue文件中直接使用即可

<template>
<div>
    姓名:{{ name }}
    年龄:{{ age }}
<button @click="changeName('李四')">改变姓名</button>
<button @click="setAge(18)">改变年龄</button>
</div>
</template>
import { state, mutations } from '@/store
 export default {
   // 在计算属性中拿到值
   computed: {
     name() {
       return state.name
     },
     age() {
       return state.age
     }
   },
   // 调用mutations里面的方法,更新数据
   methods: {
     changeName: mutations.changeName,
     setAge: mutations.setAge
   }
 }

三、原理分析

源码位置:src\core\observer\index.js

export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
  }
let ob: Observer | void
// 判断是否存在__ob__响应式属性
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
     shouldObserve &&
     !isServerRendering() &&
     (Array.isArray(value) || isPlainObject(value)) &&
 Object.isExtensible(value) &&
     !value._isVue
   ) {
 // 实例化Observer响应式对象
     ob = new Observer(value)
   }
 if (asRootData && ob) {
     ob.vmCount++
   }
 return ob
 }

Observer

export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
 def(value, '__ob__', this)
 if (Array.isArray(value)) {
 if (hasProto) {
 protoAugment(value, arrayMethods)
             } else {
 copyAugment(value, arrayMethods, arrayKeys)
             }
 this.observeArray(value)
         } else {
 // 实例化对象是一个对象,进入walk方法
 this.walk(value)
         }
 }

walk函数

 walk (obj: Object) {
 const keys = Object.keys(obj)
 // 遍历key,通过defineReactive创建响应式对象
 for (let i = 0; i < keys.length; i++) {
 defineReactive(obj, keys[i])
     }
 }

defineReactive方法

export function defineReactive (
obj: Object,
key: string,
val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
const dep = new Dep()
 const property = Object.getOwnPropertyDescriptor(obj, key)
 if (property && property.configurable === false) {
 return
   }
 // cater for pre-defined getter/setters
 const getter = property && property.get
 const setter = property && property.set
 if ((!getter || setter) && arguments.length === 2) {
     val = obj[key]
   }
 let childOb = !shallow && observe(val)
 // 接下来调用Object.defineProperty()给对象定义响应式属性
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
         dep.depend()
 if (childOb) {
           childOb.dep.depend()
 if (Array.isArray(value)) {
 dependArray(value)
           }
         }
       }
 return value
     },
 set: function reactiveSetter (newVal) {
 const value = getter ? getter.call(obj) : val
 /* eslint-disable no-self-compare */
 if (newVal === value || (newVal !== newVal && value !== value)) {
 return
       }
 /* eslint-enable no-self-compare */
 if (process.env.NODE_ENV !== 'production' && customSetter) {
 customSetter()
       }
 // #7981: for accessor properties without setter
 if (getter && !setter) return
 if (setter) {
         setter.call(obj, newVal)
       } else {
         val = newVal
       }
       childOb = !shallow && observe(newVal)
 // 对观察者watchers进行通知,state就成了全局响应式对象
       dep.notify()
     }
   })
 }
相关文章
|
6月前
|
JSON 数据格式
Vue3.0中的reactive介绍与使用
Vue3.0中的reactive介绍与使用
36 0
|
4天前
|
JavaScript 前端开发 API
vue中nextTick函数和react类似实现
vue中nextTick函数和react类似实现
7 0
|
6天前
|
JavaScript 前端开发
「Vue3系列」Vue3 事件处理
在 Vue 3 中,事件处理与 Vue 2 非常相似,但有一些细微的改进和新的语法。Vue 3 仍然使用 `v-on` 指令来处理 DOM 事件,或者更常见的是使用其简写形式 `@`。
27 0
|
6天前
|
JavaScript 前端开发
解密 Vue.observable
Vue.observable 是 Vue 2.6 引入的一个新功能,用于创建可观察的对象。它的 **`主要作用是将一个普通的 JavaScript 对象转换为一个可观察的对象,使得当对象的属性发生变化时,可以自动触发相应的响应式更新。
|
6天前
|
JavaScript 前端开发
Vue当中的observable是什么?怎么用
Vue当中的observable是什么?怎么用
21 0
|
7月前
【Vue3】vue3 中 watch 和 watchEffect 的区别
【Vue3】vue3 中 watch 和 watchEffect 的区别
40 0
|
11月前
|
JavaScript
Vue(Vue2+Vue3)——42.组件的自定义事件总结、43.TodoList案例-自定义事件
Vue(Vue2+Vue3)——42.组件的自定义事件总结、43.TodoList案例-自定义事件
|
11月前
|
JavaScript
Vue(Vue2+Vue3)——59.vuex中的四个map方法的使用
Vue(Vue2+Vue3)——59.vuex中的四个map方法的使用
|
缓存 JavaScript
vue2源码系列-深入Watcher
前面我们在 vue2源码系列-响应式原理 中介绍了 vue 中的整个响应式实现及流程,其中跳过了某些细节性的代码,现在我们再去好好学习研究一番。
|
JavaScript 前端开发
使用 Vue3 开发了四个月,回顾 emit 的用法
使用 Vue3 开发了四个月,回顾 emit 的用法
使用 Vue3 开发了四个月,回顾 emit 的用法