小宋爱睡觉 小宋爱睡觉
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
  • Vue基础
  • Vue生命周期
  • 组件通信
  • Vue-Router
  • VueX
  • Vue3
    • vue3.0相对于vue2.x有什么更新
    • proxy和defineProperty区别
    • proxy在vue中的工作原理
    • Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?
    • 监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?
    • Proxy 相比于 defineProperty 的优势
  • VirtualDOM
  • Vue
Crucials
2021-11-28

Vue3

# Vue3.0

# vue3.0相对于vue2.x有什么更新特别重要

  • 监测机制的改动:基于proxy的observer的实现,消除了Vue2.x的Object.defineProperty 的实现所存在的很多限制(对于数组的深层监听无法实现,都是将data里面的数据进行defineProperty进行绑定,后加的属性不会被绑定)

  • 只监测属性,不监测对象

    • 监测属性的添加和删除
    • 监测数组的索引和长度的变更
    • 支持map set weakmap weakset
  • 生命周期

    • 使用setup代替了原来的beforeCreate和created
  • 模板

    • 3.0版本将作用域插槽改成函数的形式,这样只会影响子组件的重新渲染,提升性能

    • 对象式组件声明方式

    • vue2.x通过声明形式传入option,和ts的结合需要通过装饰器,3.0改成类式的写法,和ts更方便结合

  • 其他

    • 支持自定义渲染

    • 支持fragment(多根节点)和portal组件

    • 基于tree shaking

# proxy和defineProperty区别特别重要

Vue2.x在实例初始化的时候遍历data对象中所有的属性,利用Object.defineProperty将这些属性转换成getter/setter,当数据发生变化自动触发setter

defineProperty是es5无法使用polyfill的特性,所以不支持ie8以下

但是defineProperty缺点

  • 无法监测添加和删除对象的属性,因为没有初始化的时候添加getter/setter,只能通过$set进行处理

  • 无法监测到数组下标和长度的变化

采用proxy来监测数据的变化,proxy是es6的功能,有以下优点

  • proxy可以直接代理整个对象而非对象属性,只需做一层代理就可以监听同级一下所有属性的变化,包括新增属性和删除属性

  • proxy可以监听数组的变化

# proxy在vue中的工作原理

  • get依赖收集

  • set delete触发依赖

  • 对于集合类型,就是在集合对象做一层包装:原方法执行后执行依赖相关的收集或者触发逻辑

# Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?特别重要

判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。

# 监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?特别重要

我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger

// 模拟 Vue 中的 data 选项 
let data = {
  msg: 'hello',
  count: 0 
}
// 模拟 Vue 实例
let vm = new Proxy(data, {
  // 当访问 vm 的成员会执行
  get (target, key) {
    console.log('get, key: ', key, target[key])
    return target[key]
  },
  // 当设置 vm 的成员会执行
  set (target, key, newValue) {
    console.log('set, key: ', key, newValue)
    if (target[key] === newValue) {
      return
    }
    target[key] = newValue
    document.querySelector('#app').textContent = target[key]
  }
})

// 测试
vm.msg = 'Hello World'
console.log(vm.msg)

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

# Proxy 相比于 defineProperty 的优势

  • 数组变化也能监听到
  • 不需要深度遍历监听

Proxy 是 ES6 中新增的功能,可以用来自定义对象中的操作

let p = new Proxy(target, handler);
// `target` 代表需要添加代理的对象
// `handler` 用来自定义对象中的操作
// 可以很方便的使用 Proxy 来实现一个数据绑定和监听

let onWatch = (obj, setBind, getLogger) => {
  let handler = {
    get(target, property, receiver) {
      getLogger(target, property)
      return Reflect.get(target, property, receiver);
    },
    set(target, property, value, receiver) {
      setBind(value);
      return Reflect.set(target, property, value);
    }
  };
  return new Proxy(obj, handler);
};

let obj = { a: 1 }
let value
let p = onWatch(obj, (v) => {
  value = v
}, (target, property) => {
  console.log(`Get '${property}' = ${target[property]}`);
})
p.a = 2 // bind `value` to `2`
p.a // -> Get 'a' = 2
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
上次更新: 2022/03/10, 14:51:31
VueX
VirtualDOM

← VueX VirtualDOM→

Copyright © 2021-2025 粤ICP备2021165371号
  • 跟随系统
  • 浅色模式
  • 深色模式