【Vue】响应式原理以及数据代理

目录

数据劫持(代理)

Vue监测数据变化原理及步骤:

一、监测对象中的数据

data对象加工成_data对象,并存入Vue实例

添加reactive getter和reactive setter:

数据变化监测效果

注意:

二、监测数组中的数据

在Vue修改数组中的某个元素需要用到以下方法:


数据劫持(代理)

数据劫持是实现数据代理的一种技术。Vue2.x中使用的是Object.defineProperty() ,因此我们有必要学习下这个函数的作用。

在MDN中有如下描述:

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

传入三个参数,被定义的对象obj、obj中的属性名、描述符。其中描述符分为数据描述法和存取描述符。这里主要使用存取描述符就可以实现数据代理。

Object.defineProperty 缺点

  • 深度监听时,需要递归到底,一次性计算量大
  • 无法监听新增属性/删除属性(所以开发中需要使用 Vue.set 和 Vue.delete 这两个 API 来增删 data 的属性)
  • 无法原生监听数组,需要特殊处理
    let a = {
        name:"badspider"
    }

    let b = {}

    object.defineProperty(b,'name',{
            get(){
                    console.log('我被调用了')
                    return  a.name
        }
            set(value){
                    console.log('我被修改了')
                    return a.name = value
            }
    })

Vue监测数据变化原理及步骤:

一、监测对象中的数据

data对象加工成_data对象,并存入Vue实例

Vue首先对options中的data对象进行加工,生成_data对象,并存入全局Vue实例中

生成_data对象:递归为每一个非对象类型的数据添加响应式的get、set方法(reactive getter、reactive setter)(数据劫持

添加reactive getter和reactive setter:

let data = {
        key1:value1,
        key2:value2,
    }

    // 创建一个观察者实例对象,用于监测data的数据变化
    const obs = new Observer(data)
    
    function Observer(obj){
        // 汇总obj中所有属性,形成一个数组keys
        const keys = Object.keys(obj)
        //Object.keys(obj) 返回值:一个表示给定对象的所有可枚举属性的字符串数组
        // 遍历keys数组(此处为简化示例,未体现属性是一个对象或一个数组进行递归的情况)
        keys.forEach((key)=>{
            Object.defineProperty(this,key,{
                get(){
                    return obj[key]
                },
                
                set(value){
                    obj[key] = value
                }
            })
        })
    }

数据变化监测效果

每个具有reactive setter的数据发生变化时,都会调用这个reactive setter,而这个reactive setter被调用时,会触发重新解析模板、生成新的虚拟DOM,、新旧虚拟DOM对比,更新内容映射到真实DOM、重新渲染这一套流程。

注意:

​ (1)在对象后追加的属性,Vue默认不做响应式处理

​ (2)如需给后添加的属性做响应式,需要使用以下API:

​ Vue.set(target,propertyName/index,value)

​ vm.$set(target,propertyName/index,value)

二、监测数组中的数据

如何监听数组变化

由于性能因素,Vue 不是通过 Object.defineProperty() 来监听数组的。

对于数组,是通过重写数组方法来实现,共修改了两处:

  • 对原生数组原型做一个备份(防止后续的操作污染原生数组原型),基于这个备份创建一个新的数组,并扩展(在执行原方法前触发一次视图更新)它的方法。
  • observer 方法中,增加对数组的处理。

在Vue修改数组中的某个元素需要用到以下方法:

​ 1.使用这些API:

push(),pop(),shift(),unshift(),splice(),sort(),erverse()

​ 2.Vue.set()或vm.$set

由于Vue本身有规定,不能把一个响应式的属性直接添加到Vue实例身上,而data对象中的所有属性最终都会通过数据代理添加到Vue实例身上,因此Vue.set()方法和this.$set()方法的targetObject这个参数不能是Vue实例本身,也不能是data对象,只能是data对象中的二级属性对象。

你可能感兴趣的:(Vue,vue,vue.js,javascript,前端)