0


同学刷抖音的间隙,我学会了Vue数据代理与数据劫持的原理

学习Vue有一段时间了,有粉丝问我,Vue的数据代理与数据劫持到底是什么意思呢?这个过程到底发生了什么呢?今天我就来详细解释一下。

一、基础知识

我们先看 Object.defineProperty()的用法:

Object.defineProperty(obj,prop,descriptor)

参数介绍:

    obj:目标对象

    prop:需要定义的属性或者方法的名字

   descriptor:prop属性所具有的特性

           可供定义的特性列表:

                    value :属性的值

                    writable:若为false,表示属性值不能重写

                    get:一旦目标属性被访问,则自动调用该方法,并返回该方法的调用结果

                    set:一旦目标属性被赋值,则自动调用该方法,进行赋值操作

                    configurable:若为false,则任何尝试删除目标属性,或修改目标属性的

                                以下特性:writable、configurable、enumerable的行为均无效

                    enumerable:若为true,则可以在for **...** in 循环或Object**.**keys()可以枚举出来

二、数据代理

1、含义

通过一个对象,代理对另一个对象的操作,即:读、写操作。

2、原理

每个 **Vue **应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:

var vm = new Vue({
  // 选项options(配置项)
})
// 数据data对象
var data = { a: 1 }

// 该data对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

上面的代码一般写成下面的形式:也就是直接在Vue函数中,传入 **data **配置对象

const vm = new MVVM({
    el: "#root",
    data: {
      a: 1
    }
  })

**数据代理的实质是: **

  1. 利用 **Object.defineProperty() **方法,给new出来的Vue实例 **vm **,添加和 **data **配置项中一模一样的属性和值。

  2. 为每一个添加到 **vm **上的属性,都指定一个 **getter/setter **

  3. 在 **getter/setter 内部去操作(读/写)data **中对应的属性

我们可以在控制台打印 **vm **,如下图

可以看到,每一个属性,都有一对 get/set getter/setter方法,这是实现响应式变化的关键

数据代理用到的Vue构造函数伪代码如下:

function MVVM(options){
    // 将选项对象保存到vm
    this.$options = options
    // 将data对象保存到 vm和 新定义的data变量中
    var data = this._data = this.$options.data
    // 将vm保存在me变量
    var me = this
    // 遍历data中所有属性名
    Object.keys(data).forEach(function (key){
        // 每次遍历,实现当前属性的代理
        me._proxy(key)
    })

    // 对data进行监视
    observe(data,this)
    // 创建一个用来编译模板的compile对象,用来解析模板以及模板里的指令
    this.$compile = new Compile(options.el || document.body, this)
}

MVVM.prototype = {
    $watch:function(key,cb,options){
        new Watcher(this,key,cb)
    },
    // 调用_proxy方法,对指定的属性实现代理
    // _proxy方法接收一个参数key,即原data对象中每个可枚举的属性的属性名
    _proxy:function(key){
        // 将vm保存在me变量
        var me = this
        // 给vm添加指定属性名的属性
        Object.defineProperty(me,key,{
            configurable:false, //不能再重新定义该属性
            enumerable:true, //可以枚举
            // 使用vm.name的形式读取属性值时,自动调用get/getter回调函数
            get:function proxyGetter(){
                return me._data[key]
            },
            // 使用vm.name = 'XXX'形式,写操作时,自动调用set/setter回调函数
            set:function proxySetter(newValue){
                me._data[key] = newValue
            }
        })
    }
}

在 **new **一个 **Vue **实例的时候,会调用上面的构造函数 **MVVM **:

构造函数 **MVVM **会接收到一个选项对象 **options **(也叫配置对象),也就是我们上面说的 **new Vue **里面的选项对象

{
el: "#root",
data: {
a: 1
}
}

接收到 **options **之后,保存在 **this.$options **中。然后将data对象中的属性赋值给 **this._data **,为了实现响应式, **vm **会对自身 **data **(注意,这是 **vm **自己的 data )进行修改,也就是通过Object.defineProperty()给每一个属性添加上 **getter **和 **setter **方法。

表面上,我们是在操作** vm.xxx **,实际上,我们操作的是 **vm._data.xxx **,也就是 **Vue 选项对象中的 data **,这就是数据代理的本质。

vm的_data中,不只是简单的选项对象中的data

尚硅谷的 Vue 全家桶课程讲解的很棒,我这里粘贴了他们的数据代理图示:

3、好处

使用数据代理,之后我们使用 **vm **,访问 **Vue **函数中 **data **的属性时,直接 this.a 就可以了,不需要使用 *this.data.a 。***注意,这里的 this,指向的是 **vm

三、数据劫持

1. 定义

在上面的数据代理讲解中,我们用到了 Object.defineProperty()方法,在每次对属性进行代理时,访问或者设置对象属性值的时候,总要触发 **get **或 **set **函数,返回需要的值或设置相应属性的值,那么,我们可以在触发函数的时候,动一点手脚,做我们自己想做的事情,这就是“数据劫持”操作。

2.vue原理

Vue的数据劫持,实战就是通过Object.defineProperty()方法来劫持对象属性的getter和setter操作,并安装一个监听器,既可以监听对象,又可以监听数组。当数据发生变化时,就发出通知。

Vue 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 **getter **和 setter 方法,在数据变动时发布消息给订阅者,触发相应的监听回调,实现响应式系统。


本文转载自: https://blog.csdn.net/czjl6886/article/details/122521879
版权归原作者 唯一的阿金 所有, 如有侵权,请联系我们删除。

“同学刷抖音的间隙,我学会了Vue数据代理与数据劫持的原理”的评论:

还没有评论