Vue2和vue3中双向数据绑定的原理,ES6的Proxy对象代理和JavaScript的Object.defineProperty,使用详细

简介:Object.defineProperty大家都知道,是vue2中双向数据绑定的原理,它是 JavaScript 中一个强大且常用的方法,用于定义对象属性,允许我们精确地控制属性的行为,包括读取、写入和删除等操作;

而Proxy是vue3中双向数据绑定的原理,是ES6中一种用于创建代理对象的特殊对象,它允许我们拦截并自定义目标对象的操作,例如属性访问、赋值、函数调用等。Proxy提供了一种机制,可以在目标对象上设置拦截器,从而拦截对目标对象的操作。

一、Object.defineProperty

1、Object.defineProperty是一个用于定义或修改对象属性的方法,可以精确地控制属性的行为,例如可写性、可枚举性和可配置性;在Object.defineProperty 方法中,有三个必需的参数和一个可选的第四参数。

  1. obj (必需):要定义属性的对象。可以是任何 JavaScript 对象。
  2. prop (必需):要定义或修改的属性的名称。可以是一个字符串,表示属性的名称。
  3. descriptor (必需):一个对象,用于定义或修改属性的特性。

还可以包含以下可选的属性:

- configurable (可选):布尔值,表示该属性是否可以被删除或修改特性。默认为 false。

- enumerable (可选):布尔值,表示该属性是否可以在 for...in 循环中被枚举。默认为 false。

- value (可选):任意类型的值,表示属性的初始值。默认为 undefined。

- writable (可选):布尔值,表示该属性的值是否可以被修改。默认为 false。

- get (可选):函数,表示获取属性值时要调用的函数。

- set (可选):函数,表示设置属性值时要调用的函数。

2、基本语法(多看注释)

javascript 复制代码
  const obj = {    name: "小明", age: 18    }
  //或者
  const obj = {    }

  //这里不能使用const,const定义的是常量,无法修改;
  let demoBute= obj.name;
  
  //使用 Object.defineProperty 定义属性名为 name 的属性
  Object.defineProperty(obj, "name", {

    //可枚举属性,可以在 for...in 循环中被枚举
    enumerable: true,
    //可配置属性,可以使用 delete 运算符删除属性
    configurable: true,

    //获取属性值的函数
    get: function () {
      console.log("获取,收集依赖");
      return demoBute
    },

    //设置属性值的函数
    set: function (value) {
      console.log("更新,通知用户");
      demoBute = value;
    }

  })
    
  //修改,触发set函数
  obj.name = "小红"
  //控制台输出:更新,通知用户
  
  //调用,出发get函数
  console.log(obj.name);
  //控制台输出:获取,收集依赖
              //小明
  
  //多次调用,看下运行顺序,按照调用顺序依次执行(set > get > log)
  //只要调用obj都会触发依赖函数
  obj.name = "小红";             //set >
  console.log(obj.name);         //get > log
  //控制台输出: 
  //更新,通知用户
  //获取,收集依赖
  //小红

3、 get和set

  • get 函数的作用是在访问属性值时被调用,它不接受任何参数,但需要返回属性的值。在示例中,我们通过return demoBute返回了name的属性值 。
  • set 函数的作用是在设置属性值时被调用,它接受一个参数 value,该参数表示要设置的属性值。在示例中,我们直接把修改后的值value 赋值给demoBute,实现更新。

**4、**注意事项

  1. get 和set 函数,不会同时被触发,它们根据属性的读取或设置操作来决定调用哪个函数;
  2. 该方法按照调用顺序,从上到下依次执行,就是有更新就只运行set函数,没更新,就只运行get函数。

二、Proxy

**1、****Proxy方法是一个允许您拦截并自定义对象的底层操作。通过使用Proxy,您可以拦截对象的各种操作,如属性访问、属性赋值、函数调用等,并在这些操作发生时执行自定义行为;在Proxy中,**target 是您要代理的目标对象, handler 是一个包含各种拦截操作的对象。 handler 对象中的每个属性都是一个特殊的拦截器,用于拦截不同的操作。

2、基本语法

javascript 复制代码
const target = {...... }

const handler = {
    get(target, property, receiver){
    //拦截属性的读取操作
    },
    set(target, property, value, receiver){
    //拦截属性
    }
}

​​​​​​​const proxy = new Proxy(target, handler);

**3、**在ES6的Proxy中,get和set是两个常用的拦截器函数,用于拦截对象属性的读取和赋值操作。下面详细介绍这两个函数的用法和功能:

(1)、get(target , property , receiver)

- target :目标对象,即被代理的对象。

- property :要访问的属性名。

- receiver:最初被调用的对象,通常是代理对象或继承代理对象的对象。 - 返回值:返回属性的值。

get 函数在访问目标对象的属性时触发,可以用来拦截属性的读取操作。您可以在 get 函数内部添加自定义的逻辑,例如记录日志、验证访问权限等。下面是一个示例:

javascript 复制代码
const target = {
  name: "Bob",
  age: 18
};
const handler = {
  get(target, property, receiver) {
    console.log(`正在读取属性:${property}`);
    return target[property];
  }
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出:正在读取属性:name,Bob
console.log(proxy.age); // 输出:正在读取属性:age,18

这里我们创建了一个代理对象 proxy ,当访问 proxy 的属性时, get 函数会被触发,并打印相应的日志信息。

(2)、set(target , property , value , receiver)

**-**target :目标对象,即被代理的对象。

**-**property :要设置的属性名。

**-**value :要设置的属性值。

**-**receiver :最初被调用的对象,通常是代理对象或继承代理对象的对象。 - 返回值:返回一个布尔值,表示属性是否设置成功。​​​​​​​

set 函数在给目标对象的属性赋值时触发,可以用来拦截属性的赋值操作。您可以在 set 函数内部添加自定义的逻辑,例如验证赋值的合法性、记录日志等。下面是一个示例:

javascript 复制代码
const target = {
  name: "Carl",
  age: 20
};
const handler = {
  set(target, property, value, receiver) {
    console.log(`正在设置属性:${property},新值为:${value}`);
    target[property] = value;
    return true;
  }
};
const proxy = new Proxy(target, handler);
proxy.age = 30; // 输出:正在设置属性:age,新值为:30
console.log(proxy.age); // 输出:30

在这里,我们给proxy的age属性赋值时,set函数会被触发,并打印相应的日志信息;通过get 和 set 拦截器函数,您可以在读取和赋值属性时执行自定义的行为,从而实现更灵活和可控的对象操作。

(3)、get和set完整实例​​​​​

javascript 复制代码
const target = {
  name: "Alice",
  age: 25
};

const handler = {
  get(target, property, receiver) {
    console.log(`正在读取属性:${property}`);
    return target[property];
  },
  set(target, property, value, receiver) {
    console.log(`正在设置属性:${property},新值为:${value}`);
    target[property] = value;
    return true;
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.name);     // 输出:正在读取属性:name,Alice
proxy.age = 30;             // 输出:正在设置属性:age,新值为:30
console.log(proxy.age);     // 输出:正在读取属性:age,30

4、handler对象中的 其它参数

  • get(target, property, receiver):拦截属性的读取操作。
  • set(target, property, value, receiver):拦截属性的赋值操作。
  • apply(target, thisArg, argumentsList):拦截函数的调用操作。
  • has(target, property):拦截in操作符的操作。
  • deleteProperty(target, property):拦截属性的删除操作
  • ......
相关推荐
拉不动的猪17 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程33 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041241 分钟前
Netty编解码器详解与实战
前端
袁煦丞1 小时前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴3 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript