为什么在vue2中改变数据视图不会更新,带你阅读源码

news2024/12/23 17:16:27

1. 监听数组变化

  • 其实 Vue 监听数组变化的原理非常简单, 就是将数组的主要方法包裹了一遍
  • 只要用户调用以下方法, 就会通知 Watcher 自动更新视图:
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

演示

工程源码: src/core/observer/array.js

// 获取数组的原型 Array.prototype, 为了方便拿到数组原有的方法
const arrayProto = Array.prototype

// 创建一个空对象 arrayMethods, 并将 arrayMethods 的原型指向 Array.prototype
export const arrayMethods = Object.create(arrayProto)

// 列出需要重写的方法
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

// 遍历列出的方法
methodsToPatch.forEach(function (method) {
  // 找到原来的函数体
  const original = arrayProto[method]
  // def 就是 defineProperty() 可以参见 util/lang.js
  def(arrayMethods, method, function mutator (...args) {
    // 调用原来的函数
    const result = original.apply(this, args)
    // 该数组是响应式的时候, 上面会有一个 __ob__ 属性
    const ob = this.__ob__
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    // 判断如果添加的元素是对象或数组, 这些处理不重要
    if (inserted) ob.observeArray(inserted)
    // 重点在这里: 每个响应式数组上都会有一个 __ob__ 利用我们保留的 __ob__ 属性获取 notify 方法来通知 Watcher 更新视图
    ob.dep.notify()
    return result
  })
})

在这里插入图片描述
**Object.create()**方法用于创建一个对象,使现有的对象作为新创建对象的原型(prototype)

总结

  • Vue 之所以能监听到数组的变化, 是因为把数组中常用的方法重新包装了一层
  • 所谓的包装就是又写了个对象, 这个对象里拥有 Array 原型中的方法, 内部也是调用的 Array 原型中的方法, 额外多调用了一下 notify() 通知 Watcher 更新视图, 最后将原型也指向 Array 的原型, 形成了一种继承关系
  • 拓展: 这种对方法的包装, 我们也称为方法的重写
  • Vue 通过对方法的重写实现了数组修改而通知视图变化, 程序员们无需学习任何新的知识, 中间的过程是完全无感的, 这种设计理念也被称为非侵入式的响应式原理, 与之对应的就是侵入式的响应式设计理念, 如: 小程序 / react
    • 小程序: setData()
    • react: setState()

2.$set 的原理

数组修改数据为什么不会被监测? 对象属性为什么可以?

网友对尤雨溪提出的 issues:

https://github.com/vuejs/vue/issues/8562

  • Vue 实现响应式原理是依赖 Object.defineProperty() 方法
  • 数组可以看做是索引和值的键值对, 同样可以被监测到
// 对象
const obj = {
  age: 18 // 键为 age 值为 18
}

// 数组
const arr = [18] // 等同于键为 0, 值为 18

监测数组

  • 通过结果可以观察出, 如果数据量提升到十万甚至百万, 对数组进行修改时, 性能损耗会非常大

  • Vue 官方通过权衡后, 觉得这样做性价比不高, 所以没有对数组进行监测

  • 尤雨溪原话

    性能代价和获得的用户体验收益不成正比。

const arr = []

defineReactive(arr, 0, 'a')
defineReactive(arr, 1, 'b')
defineReactive(arr, 2, 'c')
defineReactive(arr, 3, 'd')
defineReactive(arr, 4, 'e')

console.log(arr) // 访问数组的所有方法, 所有属性的 get 都会执行一次
arr.push('f') // 末尾追加, 所以只需要把数组中所有元素遍历一遍, 所有属性 get 都会执行一次
arr.unshift('-a') // 开头插入, 会导致数组元素顺序发生变化, 所有属性的 get 和 set 都会执行一次

演示

工程源码: src\core\observer\index.js

复习 $set 使用方法

  • $set() 有三个参数
    • 参数1: 要修改的对象 / 数组
    • 参数2: 要修改的键(索引)是什么
    • 参数3: 要设置的值是什么
export function set (target, key, val) {
  // 判断是否为数组
  if (Array.isArray(target)) {
    // 这里的操作是怕传入一个越界的索引, 往里面添加数据
    // 传入的索引和当前长度取最大值
    target.length = Math.max(target.length, key)
    // 删除原来位置的元素, 然后在当前位置添加一个数据, 就完成了替换更新
    // 而由于 splice() 是数组重写的方法, 所以会重新更新页面
    target.splice(key, 1, val)
    return val
  }
  // 如果是对象就走后面的代码, 如果是数组就不看后面的了
  if (key in target && !(key in Object.prototype)) {
    // 如果你修改的对象, 属性在原来就存在, 说明已经被劫持了
    // 直接修改对象属性即可, 会自动更新视图
    target[key] = val
    return val
  }
  const ob = target.__ob__
  if (!ob) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

总结

  • 所谓的 $set 方法, 内部做了判断, 分为以下三种情况:
    1. 如果传入的是数组, 修改数组中的元素, 就是用的 splice()
    2. 如果传入的是对象,
      1. 属性已存在于对象中, 就直接改值, 说明数据已被劫持
      2. 属性不存在于对象中, 说明这是新的属性, 所以使用 defineReactive() 进行数据劫持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/65834.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jsp servlet mysql实现的二手车汽车管理系统项目源码附带视频指导运行教程

今天给大家演示一下由jsp servlet mysql实现的一款简单的二手车汽车管理系统,系统设计采用了mvc分层的模式,结构非常清晰,功能虽简单,但是把所有可能用到的功能都实现了,往上面添加功能很简单,直接复制代码…

木聚糖-聚乙二醇-苯硼酸,PBA-PEG-Xylan,苯硼酸-PEG-木聚糖

木聚糖-聚乙二醇-苯硼酸,PBA-PEG-Xylan,苯硼酸-PEG-木聚糖 中文名称:木聚糖-苯硼酸 英文名称:Xylan-PBA 别称:苯硼酸修饰木聚糖,PBA-木聚糖 PEG接枝修饰木聚糖 木聚糖-聚乙二醇-苯硼酸 PBA-PEG-Xylan…

这样设置你的头像更容易火,自媒体7类头像优劣分析,变现路更轻松

你必须知道的知识:个人IP自媒体短视频头像设置的7种选择。 首先头像无非就是露脸的或者不露脸的两种。 其实大家做IP的话,建议大家露脸。这是在我赢助手小禾呈序个人IP培养里特别强调的,这个说的不光是你的头像,还有你的视频&…

私有化部署,加强文档管理系统稳定性

编者按:本文介绍了天翎知识文档管理系统结合群晖NAS解决方案是如何在企业系统的稳定性和安全星这块实践的。 关键词:私有化部署,外网访问,数据备份,安全技术,病毒防护 用于管理企业大量文档资料的系统&am…

A-level商务例题解析及练习market segmentatio

今日知识点:market segmentatio 例题 Q: Discuss how market segmentation could be used to improve the profitability of a hotel.解析 Answers may include: market segmentation – identify different segments within a market and target different produc…

Python for循环

Python的for循环 一、for循环 for循环:循环就是重复做某件事,for循环是python提供第二种循环机制(第一种是while循环),理论上for循环能做的事情,while循环都可以做。 目的:之所以要有for循环…

自定义HandlerMethodArgumentResolver如何注册到springmvc框架里的

目录 1.DEBUG 注册代码 1.1 WebMvcConfigurerComposite 1.2 DelegatingWebMvcConfiguration 1.3 AutowiredAnnotationBeanPostProcessor 2.DEBUG调用代码 2.1 this.argumentResolvers 日常工作开发中,总有一些参数,在未传参数时,需要自定…

零编程制作疫情全国行政区地图,理性看待各地疫情防控减码

1 前言 北京宣布,12月5日首班车起,公交、地铁不得拒绝无48小时核酸阴性证明的乘客乘车。 上海宣布,12月5日零时起,乘坐地铁、公交、轮渡,不再查验核酸检测阴性证明。 杭州和宁波深夜发布,12月5日起&…

Stable Diffusion8

也写到第八了 ~~ 这次还是和mac相关哦~~ 先吹吹,苹果亲自下场优化,在iPhone、iPad、Mac等设备上以惊人的速度运行Stable Diffusion就是这么简单。 输入一句话就能生成图像的 Stable Diffusion 已经火爆数月。它是一个开源模型,而且在消费级 GPU 上就能…

如何配置settings.py文件

文章目录配置settings.py文件1) 修改语言与时区配置2) 设置时区不敏感3) 配置项目所需数据库4)学会阅读报错信息配置settings.py文件 《settings.py配置文件(详解)》一文中,将 settings.py 配置文件的每一项给大家做了介绍。在开…

Matplotlib入门[03]——处理文本

Matplotlib入门[03]——处理文本 参考: https://ailearning.apachecn.org/Matplotlib官网Python 字符串前缀r、u、b、f含义 使用Jupyter进行练习 import matplotlib.pyplot as plt import numpy as np处理文本-基础 基础文本函数 在 matplotlib.pyplot 中&#xf…

服务访问质量(QoS)介绍与技术 二

个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。个人爱好: 编程,打篮球,计算机知识个人名言:海不辞水,故能成其大;山不辞石…

基于双参数蜜蜂算法解决车辆路径问题(Matlab代码实现)

目录 1 概述 1.1研究背景 2 运行结果 3 Matlab代码实现 4 参考文献 1 概述 群智能起源于自然环境中生物群体经过长期自然进化后具有的解决问题的能力,其中的许多问题在人类看来可以归属于高复杂度的优化问题。受到生态系统中一些具有社会群体特征的物种的行为启发,模仿自然…

python基础项目实战-简单版学生管理系统

我实现的学生管理系统主要涉及到的就是其中的增、删、改、查、显示、保存和退出这几个功能,分别将每一个功能单独用一个函数来实现的。 一、学生系统操作的主界面 二、学生系统主函数调用功能选项 三、学生系统学员的显示 四、学生系统学员的查找

window11安装docker小白教程

window11安装docker小白详细教程1、安装hyper-v2、安装wsl23、安装docker并初步运行1、安装hyper-v docker的运行依赖于linux内核,如果是windows的系统则需要安装一个运行linux的虚拟机。在window10及其以上的系统中可以安装hyper-v(Hyper-V 是微软开发…

A股交易接口如何用c++实现查询股东代码的?

A股交易接口是投资者获取股票市场数据的一个工具,使用A股交易接口能够得到更多更准确的信息,让你在股市当中,操作起来更加便捷和有效,对股市市场行情动向判断更加的准确一些。 股票交易接口支持各类数据的查询,那么今…

实现主成分分析 (PCA) 和独立成分分析 (ICA) (Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

面试题: LEAD 和 LAG 求每个用户的页面停留时长

我们先来看看这两个函数的语法: LEAD(col,n,default) OVER() 说明: 用于统计窗口内向下第n行的值参数1: 为要取值的列名参数2: 为向下第n行,默认值为1,这个值是固定的,不能动态的变化参数3&am…

Redis事务、pub/sub、PipeLine-管道、benchmark性能测试详解

一. 事务 1. 概念补充 (1). 原子性 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没…

SpringCloud Alibaba学习笔记,记重点!!

SpringCloud Alibaba入门简介 Spring Cloud Netflix 项目进入维护模式,Spring Cloud Netflix 将不再开发新的组件。Spring Cloud 版本迭代算是比较快的,因而出现了很多重大 ISSUE 都还来不及 Fix 就又推另一个 Release 了。进入维护模式意思就是目前一直…