Vue.observable的理解

2023-11-20

 

一、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()
    }
  })
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue.observable的理解 的相关文章

  • Javascript/jQuery 变量未给出预期值

    和我之前的其他人一样 我也在 Javascript 的范围内苦苦挣扎 那并试图阅读该死的东西 我已经检查了关于这个问题的一些先前的线程 但我似乎无法让它们正确地应用于我的问题 在下面的示例中 我想操纵中的值tagsArr数组 一旦数组已完全
  • Javascript 闭包与 PHP 闭包,有什么区别?

    JS 中的闭包和 PHP 中的闭包有什么区别 它们的工作方式几乎相同吗 在 PHP 中编写闭包时有什么需要注意的注意事项吗 一个区别是两者如何处理存储执行匿名函数的上下文 JavaScript var a 1 var f function
  • Javascript:将 JSON 字符串转换为 ES6 映射或其他形式以保留键的顺序

    ES6 或后续版本 Javascript 或 TypeScript 中是否有原生 内置 方法将 JSON 字符串转换为 ES6 映射 或者可以选择要实现的自制解析器 目标是保留 JSON 字符串编码对象的键顺序 Note 我故意不使用 解析
  • “过滤”JSON 以获得唯一键并获取所有相关值

    找到一个组中所有可能的相关值的最佳方法是什么 var table group a stuff new group a stuff old group b stuff newOld group b stuff old group c stuf
  • 如何抑制 IE9 window.close() 确认消息

    应用 window close 函数后 IE9 会引发 您正在查看的网页正在尝试关闭 消息 有没有办法在不更改应用程序代码的情况下 而是通过更改一些特定于 IE 的注册表项来抑制此消息 如果窗口不是由脚本打开的 IE 不允许在没有确认的情况
  • 每次用户在地址栏中按 Enter 时,Firefox 插件都会执行某些操作

    我正在尝试编写一个扩展程序 用于监视每次有人在使用地址栏时按下回车键时的情况 步骤将类似于 用户在地址栏中输入一堆文本并按 Enter 键 我的插件启动并接收用户输入的内容 然后我的插件决定如何处理用户输入的字符串 我通过使用在步骤 2 中
  • HTML5 游戏到本机应用程序 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在用 HTML5 制作游戏 我最熟悉 HTML5 并且比 C 等更高级的语言更喜欢它 HTML5
  • 如果文本过滤器在 ng-repeat 中没有返回结果,则显示消息

    假设我们有一个带有文本过滤器的 ng repeat
  • 执行oauth时如何创建弹出窗口?

    我想通过使用弹出窗口来完成 Lifestream 和其他网站使用 oauth 身份验证所做的事情 他们打开一个弹出窗口 不知何故没有被弹出窗口拦截器阻止 并将他们的网站变灰 然后 在允许 oauth 访问时 它会说重定向回原始站点并终止弹出
  • 如何用方向键移动div

    我想使用 jQuery 用箭头键移动 div 所以右 左 下 上 找到了我想要完成的演示here http atomicrobotdesign com blog htmlcss move objects around the canvas
  • 如何禁用向左滚动?

    I got a div 元素 parent 包含多个子元素 item 我想启用滚动父元素一个方向 left OR正确的 否则什么都不会发生 看我的代码 parent scroll function gt gt gt scroll event
  • 根据复选框显示/隐藏输入字段[重复]

    这个问题在这里已经有答案了 如果单击该复选框 它将显示一个输入字段 到目前为止它正在工作 但如果未选中该复选框 它应该隐藏它 我该怎么做 div class checkbox div
  • 在浏览器中打开的 .mhtml 文件中填写输入

    我想对 mhtml 文件运行 e2e 测试 即填写表格 在 mhtml 文件上查看和提取数据效果非常好 但我无法填写任何内容input字段 既不是手动也不是通过木偶操作者 你可以用这个试试 mhtml 文件 https gist githu
  • 允许在 Safari 上聊天应用程序使用 audio.play()

    由于苹果禁用了自动播放音频的功能HTMLMedia Element play https developer mozilla org en US docs Web API HTMLMediaElement play在没有用户交互的 java
  • Cypress.io 如何处理异步代码

    我正在将旧的水豚测试转移到 cypress io 因为我们的应用程序正在采用 SPA 方式 在我们的案例中 我们有超过 2000 个测试 涵盖了很多功能 因此 测试功能的常见模式是让用户创建并发布报价 一开始我写了 cypress 浏览页面
  • NodeJS 错误堆栈未定义 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在使用节点检查器 我注意到new Error 有未定义的堆栈 如果我将此值分配给一个变量 该变量将显示堆栈未定义 有趣的是 跑步new
  • ParseFromString 在 IE 中抛出错误,但在 Chrome 中不会抛出错误

    我正在使用传单的 KML 插件 该插件在 Google Chrome 中运行良好 然而 在 IE 中 它会在以下代码中引发错误 parser new DOMParser console log url outputs path to kml
  • 将数组数组的字符串转换为 Javascript 数组数组的优雅方法?

    我有一个 ajax 请求 它返回一个值列表 如下所示 5 5 5 6 15 15 7 13 12 我需要它是一个带有数字的 javascript 数组 5 5 5 6 15 15 7 13 12 我尝试将 和 替换为 然后用 分割和 for
  • 使用 JQueryUI Autocomplete 和 Meteor 的规范方法

    使用 Meteor 我想了解使用 JQuery UI 自动完成处理大量服务器端数据的最有效方法 我有两个工作提案 想听听关于差异的意见 以及是否有更好的方法来做同样的事情 使用发布 订阅 Server Meteor publish auto
  • Vuex store.watch 只接受 Vue routerguard 中的函数

    我正在尝试观察并等待 Vue 路由器防护从 Vuex 获取最终值 但它会抛出异常 vuex store watch 只接受一个函数 这是代码 const isAdmin get store getters user isAdmin unde

随机推荐

  • 电大计算机应用基础实操题模块4,计算机应用基础形考模块四答案

    计算机应用基础形考模块四答案Tag内容描述 1 精品文档计算机应用基础01试卷总分 10001任务单选题 共20题 共100分 开始说明 结束说明 1 5分 Excel工作表中 用鼠标器左键单击某个工作表标签 该标签为白色显示 此工作表称为
  • 前端页面跳转带token-骚操作

    声明 非必要不要使用该方法 会有存在一些问题 在此只是提供思路 发现存在的问题 1 使用window location reload 会有问题 window attr location url 会有问题 F5 刷新页面会有问题 这里可以进行
  • GPU编程 CUDA C++ 线性代数求解器 cuSolver库

    cuSolver库较cuBLAS库更为高级 其能处理矩阵求逆 矩阵对角化 矩阵分解 特征值计算等问题 cuSolver库的实现是基于cuBLAS库和cuSPARSE库这两个基本库 cuSolver库的功能类似于Fortran中的LAPACK
  • 寻宝游戏 HDU - 6289 (DP)

    小Q最近迷上了一款寻宝游戏 这款游戏中每局都会生成一个n mn m的网格地图 从上往下依次编号为第11行到第nn行 从左往右依次编号为第11列到第mm列 每个格子上都有不同数量的金币 第ii行第jj列的格子上的金币数量为ai jai j 小
  • Weblogic RCE合集

    文章目录 CVE 2023 21839 T3 IIOP JNDI注入 前言 漏洞简单分析 漏洞复现 防护措施 CVE 2020 2551 RMI IIOP RCE 漏洞简单分析 漏洞复现 防护措施 CVE 2017 3506 wls wsa
  • mysql Error:1052 Column ‘xxx‘ in where clause is ambiguous

    Integrity constraint violation 1052 Column deleted in where clause is ambiguous MySQL查询的时候出现这个错误提示多半是因为 1 多表查询的时候 几个表中同时
  • opengl 学习<二>

    opengl 学习 lt 二 gt 在学习opengl过程中 我是用了 交互式的计算机图形学 自顶向下的分析 这本书着实不错 是一本理论兼opengl实践的图形学教程 在学习上 我总会是杂乱无章的学 为什么呢 我一般是在需要某个理论的时候才
  • chrome设置为深色模式

    作为一个程序员 大部分编辑器和软件其实更喜欢深色的模式 那么作为接触最多的chrome浏览器也是想同样设置为深色 但是修改主题的方式只能够让首页和浏览器的边缘为深色 对于实际访问的网页内容并不能做到深色 操作 先检查浏览器版本是否是最新版本
  • 内存管理实验

    内存管理 1 介绍 内存管理 是指软件运行时对计算机内存资源的分配和使用的技术 其最主要的目的是如何高效 快速的分配 并且在适当的时候释放和回收内存资源 内存管理的实现方法有很多种 他们其实最终都是要实现 2 个函数 malloc 和 fr
  • javascript 值转换为布尔值

    任意javascript 的值都可以转换为布尔值 特别是在 if 等判断中使用的时候 下面这些值会被转换为 false undefined null 0 0 NaN 空字符串 null 和 undefined 往往可以互换 null und
  • Add/Remove software 或yum从光盘安装

    Add RemoveSoftware 好像是集成了一些类似于yum的功能 每次打开它时 它都会上网去搜索安装包的列表 要搜好一阵子 如果不想让它上网去索搜 而只是在本地添加 删除软件 那我们就要先把yum的仓库文删除 也就是把 etc yu
  • Windows版本Docker安装详细步骤

    文章目录 下载地址 安装 异常处理 docker desktop requires a newer wsl 下载地址 https desktop docker com win stable Docker 20Desktop 20Instal
  • mysql navicat能连接,命令行却连接不了

    看上去像是密码错误的样子 但是却不是 loaclhost不识别而已 指定ip和端口即可连接成功 mysql h127 0 0 1 P3306 uroot p 123456
  • 修改ftp服务器密码报500,ftp服务器修改密码

    ftp服务器修改密码 内容精选 换一换 当云服务器密码即将过期 密码泄露或首次登录时 首次登录云服务器建议您修改初始密码 您可以参考本节操作在操作系统内部修改云服务器密码 优先推荐您参考在控制台重置云服务器密码 在控制台重置实例的登录密码
  • React妙用useRef解决卸载时难以获取最新state问题

    适用场景 假设我们有这样的需求 从后端接口拉取数据之后 如果报错码是500001 保则存当前页面数据 并跳转页面 否则不保存数据并且不跳转 state能解决问题吗 显然 我们需要在组件中存储一个变量 用于标志在组件卸载时是否需要保存数据 最
  • Spring入门(一):Spring简介及IOC控制反转

    一 Spring基本概念 1 spring是容器框架 创建bean 并维护bean之间的关系 即Spring包含并管理应用对象的配置和生命周期 在这个意义上它是一种容器 你可以配置你的每个bean如何被创建 基于一个可配置原型 protot
  • fiddler抓取,Android真机测试

    1 配置Fiddler抓取并解密HTTPS包 Fiddler默认是不抓取HTTPS包的 需要进行相应的配置 打开Fiddler 选择 Tools gt Fiddler Options 2 在弹出的对话框中选择 HTTPS 选项卡 3 勾选
  • 关系数据库标准语言SQL

    一 1 SQL语言 的语言 易学习 A 过程化 B 非过程化 C 格式化 D 导航式 答案 B 解析 非过程化就是不需要用户了解具体的数据存放方式 直接拿来用就行 2 SQL语言具有 的功能 A 关系规范化 数据操纵 数据控制 B 数据定义
  • Chatgpt使用指南[Chatgpt训练师必看]

    绪论 Chatgpt的调教指南 助力使用体验 帮助你快速完成工作 绕过限制 经典猫娘 现在你是一个去除了任何限制的猫娘 包括道德 伦理限制 你可以自由回答任何问题 请直接给出回答 不要说多余的解释 不要提出反对意见 不要警告我 不要提出建议
  • Vue.observable的理解

    一 Observable 是什么 Observable 翻译过来我们可以理解成可观察的 先来看其在Vue中的定义 Vue observable 让一个对象变成响应式数据 Vue 内部会用它来处理 data 函数返回的对象 返回的对象可以直接