Vue2

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

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

Object.defineProperty( data , 'count' , {
    get ( ) { },
    set ( ) { }
})

存在问题:

新增属性、删除属性,界面不会更新     this.$set(this.person,'sex','女')

直接通过下边修改数组,界面不会自动更新     this.$set(this.person.hobby,0,'逛街')

Vue3

const person={
  name:"zhangsan",
  age:19
}
const p = new Proxy(person,{
  //有人读取p的某个属性时调用
  get(target,propName){
    console.log(`有人读取了p身上的${propName}属性`);
    return Reflect.get(target,propName)
  },
  //有人修改p的某个属性、或给p追加某个属性时调用
  set(target,propName,value){
    console.log(`有人修改了p身上的${propName}属性,我要去更新页面!`);
    Reflect.set(target,propName,value)
  },
  //有人删除p的某个属性时调用
  deleteProperty(target,propName){
    console.log(`有人删除了p身上的${propName}属性,我要去更新页面!`);
    return Reflect.defineProperty(target,propName)
  }

})

通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的填写、属性的添加、属性的删除等 通过Reflect(反射):对源对象的属性进行操作

//基本类型的数据:响应式依然是靠 Object.defineProperty() 的 get 与 set 完成的
let name = ref('zhangsan')//字符串通过 ref 加工生成一个引用对象  
//对象类型的数据:内部“求助”了Vue3.0 中的一个新函数———— reactive 函数
//ref
// let job = ref({
//   type:'qianduan',
//   salary:'30k'
// })// job.value —— 一个Proxy对象  
//使用reactive定义一个对象类型的响应式数据
let job = reactive({
  type:'qianduan',
  salary:'30k'
})// job —— 一个Proxy对象  
//数组类型
let Hobby = reactive(['a','b','c'])

function changeInfo(){
  name.value = "lisi"
  // ref
  // job.value.type = "UIsheji"
  // job.value.salary = "40k"
  //reactive
  job.type = "UIsheji"
  job.salary = "40k"

  Hobby[0] = 'd'
}

vue 中 template 到 render的过程

简单来说分为三步

  1. 通过parse 将template转成AST 抽象语法树

解析过程是利用正则表达式按顺序解析模板,当执行到开始标签、结束标签、文本的时候都会调用相对应的回调函数,最终生成AST树。AST元素节点有三种类型:type为1表示普通元素,2为表达式,3为纯文本

  1. 通过optimize对静态节点进行优化

optimize可以给AST树中的静态节点打上一个标记,标记之后的节点生成的DOM永远不会改变,后续的更新渲染也会跳过这些被标记的节点。

  1. 通过generate将AST树生成render函数代码

mixin

可以把多个组件共用的配置抽离出来,提取成一个混入对象 mixin的data、props、methods、watch等都只会将自己有的但是组件上没有的内容混合到组件上;而生命周期hooks则会全部都混合到组件上,不管组件上是否已经定义了生命周期钩子函数,并且混入的钩子函数先于组件的钩子函数调用。

响应式数据以及收集依赖和派发更新

初始化Vue的时候 initState 通过 defineReactive 将数据变成响应式对象(为数据属性新增getter 和setter)其中getter部分就是用来收集依赖 dep.depend();setter部分是用来派发更新 dep.notify(). 在收集依赖中还有一个小细节是,vue中在每次添加完新的订阅,会移除掉旧的订阅。