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

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

目录

一、基础知识

二、数据代理

1、含义

2、原理

3、好处

三、数据劫持

1. 定义

2.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 方法,在数据变动时发布消息给订阅者,触发相应的监听回调,实现响应式系统。

おすすめ

転載: blog.csdn.net/czjl6886/article/details/122521879