javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript数据劫持和数据代理

JavaScript中的数据劫持和数据代理使用

作者:遇见很ok

文章主要介绍了数据劫持(Object.defineProperty)和数据代理(Proxy)两种方式在JavaScript中的应用,并通过生活中的例子来详细解释它们的工作原理和使用场景,文章还对比了两种方式的优缺点,并指出了它们在Vue.js中的应用

一、数据劫持(Data Hijacking)

1. 生活中的例子

假设你开了一家餐厅,你雇了一个 “账房先生”(收银员),他的工作是:

现实中的“账房先生”就是 Object.defineProperty(),它拦截每个数据的读取和修改

2. 代码示例

我们用 Object.defineProperty() 来模拟这个 “账房先生”:

let bill = {};  // 创建账单对象

Object.defineProperty(bill, 'amount', {
  get() {
    console.log('客人查询了账单金额');
    return 100; // 假设账单金额是100
  },
  set(value) {
    console.log(`客人修改了账单金额为 ${value}`);
  }
});

console.log(bill.amount);  // 触发 get 方法,查询金额
bill.amount = 200;         // 触发 set 方法,修改金额

运行结果:

客人查询了账单金额
100
客人修改了账单金额为 200

问题:

二、数据代理(Data Proxy)

1. 生活中的例子

假设你家有一个 智能管家(类似于小爱同学、Siri),你可以问他:

智能管家就是 Proxy,它可以代理整个房子里所有的设备,而不需要逐个绑定(不像 Object.defineProperty() 必须单独劫持每个设备的控制)。

2. 代码示例

Proxy 实现智能管家的功能:

let house = { temperature: 22, light: 'off' }; // 房子里的设备

let smartHouse = new Proxy(house, {
  get(target, key) {
    console.log(`查询 ${key} 的状态:${target[key]}`);
    return target[key];
  },
  set(target, key, value) {
    console.log(`修改 ${key} 的状态为 ${value}`);
    target[key] = value;
    return true;
  }
});

console.log(smartHouse.temperature);  // 触发 get,查询温度
smartHouse.light = 'on';              // 触发 set,修改灯光状态

运行结果:

查询 temperature 的状态:22
修改 light 的状态为 on

Proxy 的优势:

三、对比总结

对比项数据劫持(Object.defineProperty)数据代理(Proxy)
Vue 版本Vue 2.xVue 3.x
监听对象只能监听已有的属性可以监听整个对象
监听新增/删除属性不能监听(需 Vue.set)可直接监听
监听数组需要重写数组方法原生支持
深层嵌套需要递归遍历访问时自动代理
兼容性ES5 及以上仅支持 ES6 及以上

四、再举一个更贴近开发的例子

使用 Object.defineProperty() 监听对象

let person = { name: 'Alice', age: 25 };

function makeReactive(obj) {
  for (let key in obj) {
    let value = obj[key];
    Object.defineProperty(obj, key, {
      get() {
        console.log(`读取 ${key}: ${value}`);
        return value;
      },
      set(newVal) {
        console.log(`修改 ${key} 为 ${newVal}`);
        value = newVal;
      }
    });
  }
}

makeReactive(person);

console.log(person.name);  // 读取 name
person.age = 30;           // 修改 age

问题:

使用 Proxy 监听整个对象

let person = { name: 'Alice', age: 25 };

let reactivePerson = new Proxy(person, {
  get(target, key) {
    console.log(`读取 ${key}: ${target[key]}`);
    return target[key];
  },
  set(target, key, value) {
    console.log(`修改 ${key} 为 ${value}`);
    target[key] = value;
    return true;
  },
  deleteProperty(target, key) {
    console.log(`删除属性 ${key}`);
    return delete target[key];
  }
});

console.log(reactivePerson.name);  // 读取 name
reactivePerson.age = 30;           // 修改 age
reactivePerson.newProp = 'test';   // 监听新增属性
delete reactivePerson.age;         // 监听删除属性

优势:

五、总结

概念方式适用场景优势
数据劫持Object.defineProperty()Vue 2.x兼容性好,支持老浏览器,但不能监听新增/删除属性
数据代理ProxyVue 3.x功能更强,可监听新增/删除,支持数组操作

结论:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文