CD's blog CD's blog
首页
  • HTMLCSS
  • JavaScript
  • Vue
  • TypeScript
  • React
  • Node
  • Webpack
  • Git
  • Nestjs
  • 小程序
  • 浏览器网络
  • 学习笔记

    • 《TypeScript 从零实现 axios》
    • Webpack笔记
  • JS/TS教程

    • 《现代JavaScript》教程
🔧工具方法
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

CD_wOw

内卷的行情,到不了的梦
首页
  • HTMLCSS
  • JavaScript
  • Vue
  • TypeScript
  • React
  • Node
  • Webpack
  • Git
  • Nestjs
  • 小程序
  • 浏览器网络
  • 学习笔记

    • 《TypeScript 从零实现 axios》
    • Webpack笔记
  • JS/TS教程

    • 《现代JavaScript》教程
🔧工具方法
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Vue2基础及原理

    • Vue2的生命周期
    • Vue2实用方法及原理
    • vue2 的 keepAlive 实现原理
    • Vue2的extend与手动挂载$mount
    • Vue2如何做同构SSR
    • Vue2.x之$set是怎么实现的
      • Vue 为什么要用\$set()解决对象新增属性不能响应的问题
      • \$set 源码的实现
    • vue2在TypeScript中如何使用vuex
    • Vue2.x中一些技巧及痛点问题解决方法
    • Vue2实现原理
    • Vue2 题解QA
  • Vue3基础及原理

  • 周边工具

  • Vue笔记
  • Vue2基础及原理
CD
2020-07-12
目录

Vue2.x之$set是怎么实现的

我们都知道 Vue 通过 defineProperty 对 data 内的属性进行监听,但是监听不到对象属性。那么 Vue 是怎么用 vm.$set() 解决对象新增属性不能响应的问题呢?让我们看看~

# Vue 为什么要用$set()解决对象新增属性不能响应的问题

Vue 使用了 Object.defineProperty 实现双向数据绑定,在初始化实例时对属性执行 getter/setter 转化,是对 data 内的属性进行循环监听,这就会导致对象属性,这类具有深层次的类型无法被监听。我的理解是可以看作它监听到的是对这个对象的引用的地址,只有地址发生了改变才能被监听的到。出于解决这个问题,Vue 提供了 Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)

# $set 源码的实现

源码位置:vue/src/core/instance/index.js

export function set(target: Array<any> | Object, key: any, val: any): any {
  // target 为数组
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    // 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
    target.length = Math.max(target.length, key);
    // 利用数组的splice变异方法触发响应式(splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。)
    target.splice(key, 1, val);
    return val;
  }
  // key 已经存在,直接修改属性值
  if (key in target && !(key in Object.prototype)) {
    target[key] = val;
    return val;
  }
  const ob = (target: any).__ob__;
  // target 本身就不是响应式数据, 直接赋值
  if (!ob) {
    target[key] = val;
    return val;
  }
  // 对属性进行响应式处理
  defineReactive(ob.value, key, val);
  ob.dep.notify();
  return val;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

我们阅读以上源码可知,vm.$set 的实现原理是:

  • 如果目标是数组,直接使用数组的 splice 方法触发响应
  • 如果目标是对象,会先判读属性是否存在、对象是否是响应
  • 最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理
  • defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法,详情可以看 function Observer 构造函数。setProxy
编辑 (opens new window)
#Vue2
上次更新: 2023/03/27, 21:41:56
Vue2如何做同构SSR
vue2在TypeScript中如何使用vuex

← Vue2如何做同构SSR vue2在TypeScript中如何使用vuex→

最近更新
01
gsap动画库学习笔记 - 持续~
06-05
02
远程组件加载方案笔记
05-03
03
小程序使用笔记
03-29
更多文章>
Theme by Vdoing | Copyright © 2020-2023 CD | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式