Vue源码系列21------响应式原理-----检测变化的注意事项

前端犄角旮旯,非常规面试题总结(不断更新....) 27、判断类型的方式有哪些?1、typeof操作符:用来检测数据的类型,返回的是一个表示类型的字符串。2、instanceof操作符:用来检测对象是否为指定的构造函数的实例。3、方法:可以返回对象的准确类型。4、方法:用来判断一个变量是否为数组。(一)typeof和instanceof区别typeof返回的是一个字符串,表示变量的数据类型,可能的返回值有numberstringbooleanfunctionundefinedobject。instanceof返回的是一个布尔值,true或。 阅读详情

如何处理一些特殊情况【响应式数据对于对象新增删除属性以及数组的下标访问修改和添加数据等的变化观测不到。】:我们就可以知道如何把它们也变成响应式的对象【通过Vue.set以及数组的API可以解决这些问题,本质上它们内部手动去做了依赖更新的派发。】。其实对于对象属性的删除也会用同样的问题,Vue 同样提供了 Vue.del 的全局 API,它的实现和 Vue.set 大相径庭,甚至还要更简单一些。


对象添加属性

对于使用 Object.defineProperty 实现响应式的对象,当我们去给这个对象添加一个新的属性的时候,是不能够触发它的 setter 的,比如:

var vm = new Vue({
  data:{
    a:1
  }
})
// vm.b 是非响应的
vm.b = 2

但是添加新属性的场景我们在平时开发中会经常遇到,那么 Vue 为了解决这个问题,定义了一个全局 API Vue.set 方法,它在 src/core/global-api/index.js中初始化:

Vue.set = set

这个 set 方法的定义在 src/core/observer/index.js 中:

/**
 * Set a property on an object. Adds the new property and
 * triggers change notification if the property doesn't
 * already exist.
 */
export function set (target: Array<any> | Object, key: any, val: any): any {
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  if (!ob) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

set 方法接收 3个参数,target 可能是数组或者是普通对象,key 代表的是数组的下标或者是对象的键值,val 代表添加的值。首先判断如果 target 是数组且 key 是一个合法的下标,则之前通过 splice 去添加进数组然后返回,这里的 splice 其实已经不仅仅是原生数组的 splice 了,稍后我会详细介绍数组的逻辑。接着又判断 key 已经存在于 target 中,则直接赋值返回,因为这样的变化是可以观测到了。接着再获取到 target.__ob__ 并赋值给 ob,之前分析过它是在 Observer 的构造函数执行的时候初始化的,表示 Observer 的一个实例,如果它不存在,则说明 target 不是一个响应式的对象,则直接赋值并返回。最后通过 defineReactive(ob.value, key, val) 把新添加的属性变成响应式对象,然后再通过 ob.dep.notify() 手动的触发依赖通知,在给对象添加 getter 的时候有这么一段逻辑:

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  // ...
  let childOb = !shallow && observe(val)
  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
    },
    // ...
  })
}

在 getter 过程中判断了 childOb,并调用了 childOb.dep.depend() 收集了依赖,这就是为什么执行 Vue.set 的时候通过 ob.dep.notify() 能够通知到 watcher,从而让添加新的属性到对象也可以检测到变化。这里如果 value 是个数组,那么就通过 dependArray 把数组每个元素也去做依赖收集。

数组

接着说一下数组的情况,Vue 也是不能检测到以下变动的数组:

1.当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue

2.当你修改数组的长度时,例如:vm.items.length = newLength

对于第一种情况,可以使用:Vue.set(example1.items, indexOfItem, newValue);而对于第二种情况,可以使用 vm.items.splice(newLength)。对于 Vue.set 的实现,当 target 是数组的时候,也是通过 target.splice(key, 1, val) 来添加的,在通过 observe 方法去观察对象的时候会实例化 Observer,在它的构造函数中是专门对数组做了处理,它的定义在 src/core/observer/index.js 中。

export class Observer {
  constructor (value: any) {
    this.value = value
    this.dep = new Dep()
    this.vmCount = 0
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      const augment = hasProto
        ? protoAugment
        : copyAugment
      augment(value, arrayMethods, arrayKeys)
      this.observeArray(value)
    } else {
      // ...
    }
  }
}

这里我们只需要关注 value 是 Array 的情况,首先获取 augment,这里的 hasProto 实际上就是判断对象中是否存在 __proto__,如果存在则 augment 指向 protoAugment, 否则指向 copyAugment,来看一下这两个函数的定义:

/**
 * Augment an target Object or Array by intercepting
 * the prototype chain using __proto__
 */
function protoAugment (target, src: Object, keys: any) {
  /* eslint-disable no-proto */
  target.__proto__ = src
  /* eslint-enable no-proto */
}

/**
 * Augment an target Object or Array by defining
 * hidden properties.
 */
/* istanbul ignore next */
function copyAugment (target: Object, src: Object, keys: Array<string>) {
  for (let i = 0, l = keys.length; i < l; i++) {
    const key = keys[i]
    def(target, key, src[key])
  }
}

protoAugment 方法是直接把 target.__proto__ 原型直接修改为 src,而 copyAugment 方法是遍历 keys,通过 def,也就是 Object.defineProperty 去定义它自身的属性值。对于大部分现代浏览器都会走到 protoAugment,那么它实际上就把 value 的原型指向了 arrayMethods,arrayMethods 的定义在 src/core/observer/array.js 中:

import { def } from '../util/index'

const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

/**
 * Intercept mutating methods and emit events
 */
methodsToPatch.forEach(function (method) {
  // cache original method
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args)
    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)
    // notify change
    ob.dep.notify()
    return result
  })
})

可以看到,arrayMethods 首先继承了 Array,然后对数组中所有能改变数组自身的方法,如 push、pop 等这些方法进行重写。重写后的方法会先执行它们本身原有的逻辑,并对能增加数组长度的 3 个方法 push、unshift、splice 方法做了判断,获取到插入的值,然后把新添加的值变成一个响应式对象,并且再调用 ob.dep.notify() 手动触发依赖通知,这就很好地解释了之前的示例中调用 vm.items.splice(newLength) 方法可以检测到变化。

编程初学者如何抵御技术风潮的认知陷阱 编程入门的本质不是掌握某门语言或框架,而是建立对计算逻辑、问题分解与系统思维的底层认知。当AI、Rust、WebAssembly等新概念高频涌现,初学者极易陷入‘工具即能力’的误区——把技术风潮误认为学习路径,将招聘需求等同于能力标准。这种认知偏差源于对编程本质的误解:它并非语法记忆或工具堆砌,而是持续调试、重构与验证的实践过程。真正的技术价值,在于能否用最简方案解决真实问题、能否从错误日志中定位根因、能否将模糊需求转化为可交付的代码产物。本文聚焦零基础到工程实践的关键跃迁,结合20年技术演进规律,揭示‘风 阅读详情

相关推荐

Vue-数据驱动视图(一)数据监听机制

前言 Vue的一大特点就是数据双向绑定,当数据发生变化时,也可以同时触发界面的变化,即数据驱动视图。要想实现数据驱动视图,那么有这么几个步骤: 1.收集我们需要监听的数据,并给他配置个监听器,当数据状态发生变化时触发监听器,然后判断是否需要重新渲染; 2.数据变更时重新构建虚拟DOM; 3.虚拟DOM渲染成为真实的DOM; 在这里本文主要分析其中的第一步——数据监听机制,也就是Data变化到watcher监听到的这一过程。 正文 一、Object的数据响应机制 Vu...

秋水惊鸿的博客 1540

Vue源码阅读(7):将数据转换成响应式的

1,对数据响应式处理的入口 第一小节是为了让大家了解响应式处理的代码在整体源码中的位置。 1-1,执行 new Vue(core/instance/index.js) function Vue (options) { // 执行 vm 原型上的 _init 方法,该方法在 initMixin 方法中定义 this._init(options) } // 写入 vm._init initMixin(Vue) vue 里面执行 _init 方法,该方法定义在 initMixin 方法中。

f18855666661的博客 2095

云安全技术——搭建VPN

VPN(Virtual Private Network)是一种可以在公共网络上建立安全连接的技术。VPN是实现保密通信的基本手段,在windows系统上,可以直接进行VPN服务的搭建。1.VPN的工作原理:通过使用加密协议和认证机制,将本地计算机和远程服务器之间的通信加密和保护。2.VPN的分类:根据不同的方式和用途,VPN可以分为不同类型,例如远程访问VPN、站点到站点VPN等。3.VPN的优势:VPN可以带来许多好处,如提高数据安全性、隐藏真实IP地址、突破地理限制等。4.

qq_53142796的博客 3万+

Vue源码 深入响应式原理 (三)nextTick & 检测变化的注意事项

Vue源码 深入响应式原理 (三)nextTick & 检测变化的注意事项nextTickJS 运行机制Vue 的实现总结检测变化的注意事项对象添加属性数组总结Vue源码学习目录 学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:《Vue.js2.0 源码揭秘》、 黄轶老师拉钩教育教程地址:《Vue.js 3.0 核心源码解析》 这里分析的源码是Runtime + Compiler 的 Vue.js 调试代码在:node_modules\vue\dist\vue.esm.js 里添加

陈坚泓的博客 833

大疆上云API-1.10.0版本-设备位置数据实时处理与WebSocket推送实战解析

本文深入解析了大疆上云API 1.10.0版本中设备位置数据的实时处理与推送全链路。通过剖析源码,详细阐述了从MQTT接收OSD数据、Spring Integration路由分发、业务逻辑处理到WebSocket实时推送至前端地图的核心流程,并提供了实战优化与避坑指南,帮助开发者构建高可靠的无人机实时定位系统。

weixin_29291863的博客 412

一个完整的c#股票分析软件源码

完整的c#股票分析软件源码

qq_35600909的博客 4595

Vue中改变对象响应式注意事项

数组更改注意事项 Vue无法检测到以下方式变动的数组 当你利用索引直接设置一个项时,例如:vm.items[index] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength 针对问题一,解决方案有两种: var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) // 问题 vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是

CiCi2012_3_6的专栏 478

LM Studio Bionic:本地AI智能体从部署到实战完整指南

AI智能体作为能够自主规划、执行多步任务的人工智能系统,其核心原理在于结合大语言模型的推理能力与工具调用机制。通过状态保持和任务分解算法,智能体实现了从单次问答到持续协作的技术跃迁。在工程实践中,这种架构显著降低了复杂任务自动化的门槛,特别适用于数据敏感场景和定制化需求。以Tesla V100等专业硬件为例,本地部署能充分发挥其大显存优势,支持更高精度的模型量化格式。在实际应用层面,智能体可无缝集成到代码审查、文档生成等开发工作流中,而LM Studio Bionic通过统一界面整合了模型服务、任务规划器等

weixin_29053695的博客 650

Vue源码探究-数据绑定的实现

Vue源码探究-数据绑定的实现 本篇代码位于vue/src/core/observer/ 在总结完数据绑定实现的逻辑架构一篇后,已经对Vue的数据观察系统的角色和各自的功能有了比较透彻的了解,这一篇继续仔细分析下源码的具体实现。 Observer // Observer类用来附加到每个观察对象上。 // 将被观察目标对象的属性键名转换成存...

weixin_33895657的博客 240

目前固态激光雷达在机器人领域的应用难点汇总

固态激光雷达在机器人领域面临性能与成本的双重挑战:探测性能上,动态范围不足(60-80dB)导致高/低反射物体识别困难,近距盲区(30-50cm)与长距精度(±3cm)矛盾突出;结构上视场角与点云密度难以平衡,多雷达拼接又带来同步误差。成本方面,核心元件(SPAD/OPA芯片)良率低(<50%)、校准工序复杂,单机成本超200美元。环境适应性上,粉尘附着、振动偏移(±2°)和光衰(1万小时衰减15%)制约可靠性。

start_up_go的博客 481

搞定ESD(五):静电放电问题分析与调试

前面深入分析了静电放电的干扰机理、耦合路径,从现在开始将进入下一个大家非常关注的环节:静电放电问题分析与调试,掌握静电放电问题的分析方法,快速锁定敏感设备或者耦合路径,可以达到事半功倍的效果。

记得诚 2794

Vue源码解析:数据双向绑定(响应式)原理之别再说发布者-订阅者模式

每当去找工作面试的时候,当面试官问到vue的双向数据绑定或者响应式原理的时候,面试者总是不加思索的张口就来:采用发布者-订阅者模式。。。。。一顿神侃。真不知道是梁静茹给了你们多少勇气说出的这句话。这么说一定会被面试官认为是背过题的。那么vue的双向数据绑定(响应式)原理到底是什么呢?这还是得从vue的源码说起: 我们知道vue的一大特点是数据驱动视图,如何理解数据驱动视图这六个字呢? 数据:可以理解为state; 驱动:这里应该是一个动词,就是操作的意思,就是render函数; 视图:就是页面的UI

lee前端技术站 2135

TC3XX - MCAL知识点(十一):WDG EB-tresos配置说明与代码浅析

在AUTOSAR中,看门狗栈实现了三种监控机制:实时监控:用于周期软件的定时监控期限监督:针对非周期软件逻辑监督:用于监督执行顺序的正确性看门狗(WDG)驱动实现AUTOSAR(4.2.2)中规定的看门狗SWS,提供初始化、改变操作模式和设置触发条件(超时)等服务,供看门狗硬件(WDT)用户使用。WDG驱动的用户包括:模式管理模块(用于初始化),WdgM通过Wdglf设置触发条件和驱动运行模式设置。WdgM实施上述监督机制。AUTOSAR扩展触发概念,以支持窗口看门狗模式。

梦想技术家 3601

三、Vue响应式原理和计算方法

Vue 响应式系统核心原理

nsdhakshda的博客 421

MATLAB和S7-1200PLC水箱液位高度PID控制联合仿真(KEPserverOPC通信应用)

SMART PLC 向导PID的详细介绍请查看下面文章链接:S7-200 SMART PLC PID向导详细介绍(如何实现P、PD、PID控制器)-优快云博客文章浏览阅读1k次。这篇博客主要介绍SMART PLC PID向导的使用,PID控制相关的其它内容请查看专栏系列文章,常用链接如下:SMART PLC PID负压控制(过程量为负数)_负压控制pid控制程序_RXXW_Dor的博客-优快云博客1、如何实现PID反作用调节?S7-1200PLC和KEPserver OPC通信-优快云博客。

RXXW_Dor的博客 1781

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Vue知识点总结(21)——对象的变更检测(超级详细)

vue官方文档中的深入响应式原理中有提到过,对于检测变化的一些注意事项。 由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 这句话是啥意思呢? 我们先看一个小例子。 <div id="app"> <h3>{{user.name}},{{user.age}}</h3> <button @click='handlerAdd'>添加属性</button>

CreatorRay的博客 790

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

十四、Vue数据监测原理————温开水的复习笔记

数据监测、数据代理。让一个对象数据(属性)可以获取get与修改set另一个对象数据~~~ 追加一个有响应式性质的属性~~~

qq_47286790的博客 467

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

vue(vue2)

vue.

qq_41950754的博客 913

vue cli 地址栏有变化而页面不变_Vue核心98道面试题总结

阅读文档 47道HTTP面试题总结本文档基于vue-cli技术栈总结了vue-cli工程vue.js核心知识vue-router路由vuex状态管理器axios等http请求移动端适配Tab切换等常用功能vue与原生app混合交互vue生产环境部署vue各项技术源码解析MVVM设计模式vue-cli工程深入拓展等12个关于vue-cli开发的方面。不仅可以帮你一次性详细阅读所有关于vue的面试题、...

weixin_39608559的博客 129

Vue中的变异数组

心余力绌的对象 在Vue中,如果直接修改对象属性的值,将不会触发响应式,就是说在改变数据的同时,页面内容并不会随之改变。 这是什么原因? 原因在于:Vue的响应式系统是基于 Object.defineProperty() 这个方法的,该方法可以监听对象中某个元素的获取或修改,经过了该方法处理的数据,我们称其为响应式数据。但是,该方法有一个很大的缺点,新增属性或者删除属性不会触发监听。 ...

qq_34865249的博客 917

Cannot set reactive property on undefined, null, or primitive value:null解决

用了el-switch,在v-model那里我先写了v-model=“switch”,结果有红色下划线。 我就神经短路改成了this.switch。 然后在新网页打开那个switch,点击就会报如上错。 不能用this.value的形式!有下划线是因为官方不允许用JS关键字switch做value的名字,改下value的名字就好了。 ...

我爱美女S的博客 1万+

vue 修改对象的值视图没有发生改变_从源码解惑,为什么明明修改了数据视图却不更新__Vue.js...

问题描述在使用Vue日常工作开发中,偶尔会遇到这种问题,明明我已经修改了数据,但是视图却没有更新。比如下面这些骚操作:直接在对象上新增属性直接删除对象属性通过角标[]直接修改数组的某一项直接修改数组的length问题分析想要了解为什么上面这些写法不会触发视图更新,只需要搞清楚在vue中是如何对数据进行响应式处理的。知道了vue的数据响应机制,那么跳出机制的写法自然就不能触发视图更新了。在vue中,...

weixin_32310195的博客 903

【探究Vue原理】对Vue2.0的数据响应式的探究

目录开篇1. 开篇     开篇 关于Vue 1.0中响应式的分析可以看我这篇博文。 与Vue1相比Vue2引入了虚拟DOM,这大大优化了Vue在大项目中的表现。本文会分析什么是虚拟DOM,为什么要引入它,它又是怎么工作的。 之后再谈谈什么是响应式,它又是如何实现的。以及响应式与虚拟DOM之间的关联。 我会尽量详细的阐述文中可能涉及的一切知识,文章可能稍显冗长,我会将可跳过的地...

杨光的博客 682

vue源码解析之observe

一. vue文档中有“由于 JavaScript 的限制,Vue 不能检测以下数组的变动”,是否真是由于JavaScript的限制,还是出于其他原因考虑 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength   第一种情况是利用索引设置一个...

weixin_30883271的博客 245

深入理解响应式原理(二)

派发更新 通过上一节分析我们了解了响应式数据依赖收集过程,收集的目的就是为了当我们修改数据的时候,可以对相关的依赖派发更新,那么这一节我们来详细分析这个过程。 我们先来回顾一下 setter 部分的逻辑: /** * Define a reactive property on an Object. */ export function defineReactive ( obj: O...

messizhao的博客 386
上一篇: Vue源码系列20------响应式原理----nextTick
下一篇: markdown语法
Emily Qin
博客等级 码龄10年 118粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值