Vue面試中observable原理詳解
一、Observable 是什么
Observable
翻譯過來我們可以理解成可觀察的
我們先來看一下其在Vue
中的定義
Vue.observable
,讓一個(gè)對象變成響應(yīng)式數(shù)據(jù)。Vue
內(nèi)部會用它來處理 data
函數(shù)返回的對象
返回的對象可以直接用于渲染函數(shù)和計(jì)算屬性內(nèi),并且會在發(fā)生變更時(shí)觸發(fā)相應(yīng)的更新。也可以作為最小化的跨組件狀態(tài)存儲器
Vue.observable({ count : 1})
其作用等同于
new vue({ count : 1})
在 Vue 2.x
中,被傳入的對象會直接被 Vue.observable
變更,它和被返回的對象是同一個(gè)對象
在 Vue 3.x
中,則會返回一個(gè)可響應(yīng)的代理,而對源對象直接進(jìn)行變更仍然是不可響應(yīng)的
二、使用場景
在非父子組件通信時(shí),可以使用通常的bus
或者使用vuex
,但是實(shí)現(xiàn)的功能不是太復(fù)雜,而使用上面兩個(gè)又有點(diǎn)繁瑣。這時(shí),observable
就是一個(gè)很好的選擇
創(chuàng)建一個(gè)js
文件
// 引入vue import Vue from 'vue // 創(chuàng)建state對象,使用observable讓state對象可響應(yīng) export let state = Vue.observable({ name: '張三', 'age': 38 }) // 創(chuàng)建對應(yīng)的方法 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 { // 在計(jì)算屬性中拿到值 computed: { name() { return state.name }, age() { return state.age } }, // 調(diào)用mutations里面的方法,更新數(shù)據(jù) 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__響應(yīng)式屬性 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 ) { // 實(shí)例化Observer響應(yīng)式對象 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 { // 實(shí)例化對象是一個(gè)對象,進(jìn)入walk方法 this.walk(value) } }
walk
函數(shù)
walk (obj: Object) { const keys = Object.keys(obj) // 遍歷key,通過defineReactive創(chuàng)建響應(yīng)式對象 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) // 接下來調(diào)用Object.defineProperty()給對象定義響應(yīng)式屬性 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進(jìn)行通知,state就成了全局響應(yīng)式對象 dep.notify() } }) }
以上就是Vue面試中observable原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue observable原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
原生JS實(shí)現(xiàn)Vue transition fade過渡動畫效果示例
這篇文章主要為大家介紹了原生JS實(shí)現(xiàn)Vue transition fade過渡動畫效果示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06詳解vue-cil和webpack中本地靜態(tài)圖片的路徑問題解決方案
這篇文章主要介紹了詳解vue-cil和webpack中本地靜態(tài)圖片的路徑問題解決方案,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-09-09Nginx部署Vue.js前端項(xiàng)目的實(shí)現(xiàn)
本文主要介紹了Nginx部署Vue.js前端項(xiàng)目指南,幫助您實(shí)現(xiàn)從開發(fā)到線上部署的平滑過渡,確保用戶能夠獲得最佳的訪問體驗(yàn),感興趣的可以了解一下2024-09-09Vue-cli中post請求發(fā)送Json格式數(shù)據(jù)方式
這篇文章主要介紹了Vue-cli中post請求發(fā)送Json格式數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04Vue自定義指令實(shí)現(xiàn)checkbox全選功能的方法
下面小編就為大家分享一篇Vue自定義指令實(shí)現(xiàn)checkbox全選功能的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02vue中created、watch和computed的執(zhí)行順序詳解
由于vue的雙向數(shù)據(jù)綁定,自動更新數(shù)據(jù)的機(jī)制,在數(shù)據(jù)變化后,對此數(shù)據(jù)依賴?的所有數(shù)據(jù),watch事件都會被更新、觸發(fā),下面這篇文章主要給大家介紹了關(guān)于vue中created、watch和computed的執(zhí)行順序,需要的朋友可以參考下2022-11-11Elementui如何限制el-input框輸入小數(shù)點(diǎn)
這篇文章主要介紹了Elementui如何限制el-input框輸入小數(shù)點(diǎn),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08