• 每日一题之Vue数据劫持原理是什么?


    什么是数据劫持?

    定义: 数据劫持,指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。

    简单地说,就是当我们 触发函数的时候 动一些手脚做点我们自己想做的事情,也就是所谓的 "劫持"操作

    数据劫持的两种方案:

    • Object.defineProperty
    • Proxy

    1).Object.defineProperty

    • 语法:

    Object.defineProperty(obj,prop,descriptor)

    • 参数:

      • obj:目标对象
      • prop:需要定义的属性或方法的名称
      • descriptor:目标属性所拥有的特性
    • 可供定义的特性列表:

      • value:属性的值
      • writable:如果为false,属性的值就不能被重写。
      • get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。
      • set:一旦目标属性被赋值,就会调回此方法。
      • configurable:如果为false,则任何尝试删除目标属性或修改属性性以下特性(writable, configurable, enumerable)的行为将被无效化。
      • enumerable:是否能在for…in循环中遍历出来或在Object.keys中列举出来。

    例子

    在Vue中其实就是通过Object.defineProperty来劫持对象属性的settergetter操作,并“种下”一个监听器,当数据发生变化的时候发出通知,如下:

    var data = {
       name:'test'}
    Object.keys(data).forEach(function(key){
       
        Object.defineProperty(data,key,{
       
            enumerable:true,
            configurable:true,
            get:function(){
       
                console.log('get');
            },
            set:function(){
       
                console.log('监听到数据发生了变化');
            }
        })
    });
    data.name //控制台会打印出 “get”
    data.name = 'hxx' //控制台会打印出 "监听到数据发生了变化"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    参考 前端vue面试题详细解答

    上面的这个例子可以看出,我们完全可以控制对象属性的设置和读取。在Vue中,在很多地方都非常巧妙的运用了Object.defineProperty这个方法,具体用在哪里并且它又解决了哪些问题,下面就简单的说一下:

    监听对象属性的变化

    它通过observe每个对象的属性,添加到订阅器dep中,当数据发生变化的时候发出一个notice。 相关源代码如下:(作者采用的是ES6+flow写的,代码在src/core/observer/index.js模块里面)

    export function defineReactive (
      obj: Object,
      key: string,
      val: any,
      customSetter?: Function
    ) {
       
      const dep = new Dep()//创建订阅对象  
      const property = Object.getOwnPropertyDe述  //属性的描述特性里面如果configurable为false则属性的任何修改将无效  
      if (property && property.configurable === false) {
        return }scriptor(obj, key)//获取obj对象的key属性的描
        // cater for pre-defined getter/setters  
        const getter = property && property.get  
        const setter = property && property.set
      let childOb = observe(val)//创建一个观察者对象  
      Object.defineProperty(obj, key, {
       
        enumerable: true,//可枚举    
        configurable: true,//可修改    
        get: function reactiveGetter () {
       
          const value = getter ? getter.call(obj) : val//先调用默认的get方法取值      //这里就劫持了get方法,也是作者一个巧妙设计,在创建watcher实例的时候,通过调用对象的get方法往订阅器dep上添加这个创建的watcher实例      if (Dep.target) {
       
            dep.depend()
            if (childOb) {
       
              childOb.dep.depend()
            }
            if (Array.isArray(value
    • 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
  • 相关阅读:
    RAW-GNN: RAndom Walk Aggregation based Graph Neural Network
    Json-server 模拟后端接口
    ROS2系列知识(3):环境配置
    【MM32F5270开发板试用】完成简易智能家居
    决策树的优缺点
    红蓝对抗-红队打点的那些事
    ATTENTION, LEARN TO SOLVE ROUTING PROBLEMS!
    基于STM32结合CubeMX学习Free-RT-OS的源码之信号量与互斥量
    Python基础语法(2)
    java毕业设计开题报告超市积分管理系统
  • 原文地址:https://blog.csdn.net/bb_xiaxia1998/article/details/127764024