Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 前端面试题

  • JavaScript

  • Vue2

  • port

  • CSS

  • Node.js

  • JavaScript优化

  • uniapp

  • Mini Program

  • TypeScript

  • 面向对象编程

  • UI组件

  • Plugin

  • Vue3

    • 教程

      • 创建Vue3工程

      • Composition API

        • setup
        • ref函数
        • reactive函数
        • 响应式原理
          • 响应式原理
            • vue2.x的响应式
            • Vue3.0的响应式
          • 举例
        • reactive对比ref
        • setup的两个注意点
        • 计算属性与监视
        • 生命周期
        • 自定义hook函数
        • toRef
        • shallowReactive 与 shallowRef
        • readonly 与 shallowReadonly
        • toRaw 与 markRaw
        • customRef
        • provide 与 inject
        • 响应式数据的判断
        • Vue3通信方式
      • Composition API 的优势

      • 新的组件

      • 其他新变化

    • Vue Router

    • API

    • Vuex

    • 实例处理方案

    • 文档

    • 用法

  • 性能优化

  • Axios

  • 状态管理

  • React

  • Mock

  • Icon

  • Template

  • 构建工具

  • 项目规范配置

  • Taro

  • SVG

  • React Native

  • 前端
  • Vue3
  • 教程
  • Composition API
HiuZing
2023-02-06
目录

响应式原理

# 响应式原理

# vue2.x的响应式

  • 实现原理:

    • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。

    • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

      Object.defineProperty(data, 'count', {
          get () {}, 
          set () {}
      })
      
      1
      2
      3
      4
  • 存在问题:

    • 新增属性、删除属性, 界面不会更新。

    • 直接通过下标修改数组, 界面不会自动更新。

      // 新增
      methods:{
          addSex(){
              this.$set(this.person,'sex','女')
              // 或者 引入 import Vue from 'vue'
              // Vue.set(this.person,'sex','女')
          }
      }
      // 删除
      deleteName(){
          this.$delete(this.person,'name')
      }
      // 修改数组
      updateHobby(){
          this.$set(this.person.hobby,0,'逛街')
          // 或者
          this.person.hobby.splice(0,1,'逛街')
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18

# Vue3.0的响应式

在目标对象架设一层“拦截”,当外界对该对象进行访问时,需要经过这层拦截,而Proxy充当这种机制,类似于“代理”的意思,可以在外界访问该对象前进行过滤和修改

  • 实现原理:

    • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。

    • 通过Reflect(反射): 对源对象的属性进行操作。

    • MDN文档中描述的Proxy与Reflect:

      • Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

      • Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

        new Proxy(data, {
            // 拦截读取属性值
            get (target, prop) {
                return Reflect.get(target, prop)
            },
            // 拦截设置属性值或添加新属性
            set (target, prop, value) {
                return Reflect.set(target, prop, value)
            },
            // 拦截删除属性
            deleteProperty (target, prop) {
                return Reflect.deleteProperty(target, prop)
            }
        })
        
        proxy.name = 'tom'   
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

# 举例

// 源数据
let person = {
  name: '张三',
  age: 18
}

// 模拟Vue2中实现响应式
let p = {}
Object.defineProperty(p, 'name', {
  configurable:true,
  // 有人读取name调用
  get() {
    return person.name
  },
  //
  set(value) {
    person.name = value
  }
})

// 模拟Vue3中实现响应式
const p = new Proxy(person, {
  // 有人读取p的某个属性时调用
  get(target, propName) {
    console.log(`有人读取了p身上的${propName}某个属性`)
    return Reflect.get(target, propName)
  },
  // 有人修改p某个属性或者追加某个属性时调用
  set(target, propName, value) {
    console.log(`有人修改了p身上的${propName}某个属性`)
    return Reflect.set(target, propName, value)
  },
  // 有人删除p的某个属性时调用
  defineProperty(target, propName) {
    console.log(`有人删除了p身上的${propName}某个属性`)
    return Reflect.deleteProperty(target, propName)
  }
})

let obj = {a: 1, b: 2}

// 通过Object.defineProperty去操作
try {
  Object.defineProperty(obj, 'c', {
    get() {
      return 3
    }
  })
  Object.defineProperty(obj, c, {
    get() {
      return 4
    }
  })
} catch (err) {
  console.log(err)
}


// 通过Reflect.defineProperty去操作
const x1 = Reflect.defineProperty(obj, 'c', {
  get() {
    return 3
  }
})
const x2 = Reflect.defineProperty(obj, 'c', {
  get() {
    return 4
  }
})
console.log(x2)
if (x2) {
  console.log('成功')
} else {
  console.log('失败')
}
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
上次更新: 2024/08/14, 04:14:33
reactive函数
reactive对比ref

← reactive函数 reactive对比ref→

最近更新
01
React Native 使用SVG
08-13
02
Docker基础命令
08-04
03
算数逻辑单元
07-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 WeiXiaojing | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式