【JavaScript】关于数据劫持

突然想到了两种模式。观察者模式和消息订阅与发布模式。本文会简单的梳理一下Vue当中所用到的观察者模式所实现的数据劫持。

我是按照我的理解,对数据劫持进行了倒推,方便理解。

比如:我要对一个对象进行劫持,检测这个对象某个属性发生了变化,那我需要先有个对象,然后再对这个对象进行劫持。

const data = { name: 'Vue' };  
observe(data);  

这里的observe方法就是一个观察方法。先看一下代码

// 递归地将对象的所有属性都转换为响应式的  
  function observe(value) {  
    if (!isObject(value)) {  
      return;  
    }  
    if (typeof value === 'object') {  
      Object.keys(value).forEach(key => {  
        defineReactive(value, key, value[key]);  
      });  
    }  
  }  

这个方法接收对象之后进行了一个判断(是否为对象类型),核心劫持的逻辑就在defineReactive这个代码。

function defineReactive(obj, key, val) {  
    // 递归地将所有属性都转换为响应式的  
    observe(val);  
    
    // 创建一个内部依赖列表  
    const dep = new Dep();  
    
    // 使用Object.defineProperty来定义属性的getter和setter  
    Object.defineProperty(obj, key, {  
      enumerable: true, // 可枚举  
      configurable: true, // 可配置  
      get: function reactiveGetter() {  
        // 当属性被访问时,通知依赖  
        Dep.target && dep.depend();  
        return val;  
      },  
      set: function reactiveSetter(newVal) {  
        // 检查新值是否与旧值相同  
        if (newVal === val) return;  
        // 更新值  
        val = newVal;  
        // 递归地将新值转换为响应式的  
        observe(newVal);  
        // 通知所有依赖该属性的watcher更新  
        dep.notify();  
      }  
    });  
  }  

这里面有一个依赖(Dep)

// 依赖收集类  
  class Dep {  
    constructor() {  
      this.subscribers = new Set();  
    }  
    
    depend() {  
      if (Dep.target) {  
        this.subscribers.add(Dep.target);  
      }  
    }  
    
    notify() {  
      this.subscribers.forEach(subscriber => {  
        subscriber.update();  
      });  
    }  
  }  
    
  // 存放当前正在计算的watcher  
  Dep.target = null;  

 最后就是观察数据了

// 简单的watcher类  
  class Watcher {  
    constructor(obj, key, cb) {  
      Dep.target = this; // 将当前watcher设置为Dep.target  
      this.cb = cb;  
      this.obj = obj;  
      this.key = key;  
      // 触发getter,导致依赖收集  
      this.value = obj[key];  
      Dep.target = null; // 清理Dep.target  
    }  
    
    update() {  
      this.cb(this.obj[this.key]);  
    }  
  }  

通过触发这个类,来监听我们想要监听的数据

const watcher = new Watcher(data, 'name', function(newVal) {  
    console.log(`name has changed to ${newVal}`);  
  });  

修改data的name属性就可以出发上面的打印

下面为完整代码

function defineReactive(obj, key, val) {  
    // 递归地将所有属性都转换为响应式的  
    observe(val);  
    
    // 创建一个内部依赖列表  
    const dep = new Dep();  
    
    // 使用Object.defineProperty来定义属性的getter和setter  
    Object.defineProperty(obj, key, {  
      enumerable: true, // 可枚举  
      configurable: true, // 可配置  
      get: function reactiveGetter() {  
        // 当属性被访问时,通知依赖  
        Dep.target && dep.depend();  
        return val;  
      },  
      set: function reactiveSetter(newVal) {  
        // 检查新值是否与旧值相同  
        if (newVal === val) return;  
        // 更新值  
        val = newVal;  
        // 递归地将新值转换为响应式的  
        observe(newVal);  
        // 通知所有依赖该属性的watcher更新  
        dep.notify();  
      }  
    });  
  }  
    
  // 依赖收集类  
  class Dep {  
    constructor() {  
      this.subscribers = new Set();  
    }  
    
    depend() {  
      if (Dep.target) {  
        this.subscribers.add(Dep.target);  
      }  
    }  
    
    notify() {  
      this.subscribers.forEach(subscriber => {  
        subscriber.update();  
      });  
    }  
  }  
    
  // 存放当前正在计算的watcher  
  Dep.target = null;  
    
  // 简单的watcher类  
  class Watcher {  
    constructor(obj, key, cb) {  
      Dep.target = this; // 将当前watcher设置为Dep.target  
      this.cb = cb;  
      this.obj = obj;  
      this.key = key;  
      // 触发getter,导致依赖收集  
      this.value = obj[key];  
      Dep.target = null; // 清理Dep.target  
    }  
    
    update() {  
      this.cb(this.obj[this.key]);  
    }  
  }  
    
  // 递归地将对象的所有属性都转换为响应式的  
  function observe(value) {  
    if (!isObject(value)) {  
      return;  
    }  
    if (typeof value === 'object') {  
      Object.keys(value).forEach(key => {  
        defineReactive(value, key, value[key]);  
      });  
    }  
  }  
    
  function isObject(value) {  
    return value !== null && typeof value === 'object';  
  }  
    
  // 示例用法  
  const data = { name: 'Vue' };  
  observe(data);  
    
  const watcher = new Watcher(data, 'name', function(newVal) {  
    console.log(`name has changed to ${newVal}`);  
  });  
    
  // 修改name属性以触发watcher  
  data.name = 'Reactivity';

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值