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、基本语法(多看注释)

  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、基本语法

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 函数内部添加自定义的逻辑,例如记录日志、验证访问权限等。下面是一个示例:

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 函数内部添加自定义的逻辑,例如验证赋值的合法性、记录日志等。下面是一个示例:

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完整实例​​​​​

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):拦截属性的删除操作
  •  ......
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: Vue3 和 Vue2 双向绑定之间最大的区别是,Vue3 将双向绑定替换为响应式组件系统,它使用可观察的属性来替换双向绑定,从而提供更快、更简单的编程体验。另外,Vue3 增加了对 TypeScript 的支持,以便更好地支持大型应用程序的开发,并改进了渲染性能和内存使用,以提高网页的加载速度。 ### 回答2: Vue3和Vue2的双向绑定在实现方式和性能优化上有一些区别。 首先,Vue2使用的是基于ES5的Object.defineProperty方法来实现双向绑定。这种方式需要遍历对象的所有属性,并为每个属性添加getter和setter方法。而Vue3使用的则是ES6Proxy对象Proxy可以直接代理目标对象并监听目标对象的所有操作,因此无需遍历属性并创建getter和setter。这使得Vue3在初始化和更新过程更快。 其次,在Vue2,每个data属性都需要在实例化Vue对象时定义。而在Vue3,可以在组件内部使用reactive方法将任意Javascript对象转化为响应式对象。这使得创建和修改响应式数据更加灵活,并且避免了在Vue2需要使用data选项定义所有属性的冗余。 另外,Vue3引入了Composition API,这是一种新的API风格,使组件的逻辑更加模块化和可复用。Composition API允许我们将相关的功能逻辑放到一起,而不是按照生命周期钩子函数划分。这使得代码更易于理解和维护。 此外,由于Vue3改用了ES模块来编写,使它的代码更加模块化和易于管理。它也进行了一系列的性能优化,包括对静态节点的处理、优化了虚拟DOM的生成和渲染。 总结起来,Vue3在双向绑定采用Proxy代理对象来替代Object.defineProperty,使其初始化和更新更加高效。通过引入Composition API,使组件逻辑更加模块化和可复用。它还进行了一系列的性能优化,提升了整体性能。 ### 回答3: Vue2双向数据绑定是通过v-model指令实现的,它将表单元素的值与Vue实例数据进行绑定,一旦用户在表单元素输入数据,该数据会自动更新到Vue实例的对应属性,同时也可以通过修改Vue实例的属性来改变表单元素的值。这种双向绑定的实现依赖于Vue的“响应式系统”,通过对数据对象进行劫持来实现属性值的变更监听。当一个被绑定数据发生改变时,Vue会自动更新对应的视图。 而Vue3双向绑定则有所改变。Vue3不再使用v-model指令作为双向绑定的入口,取而代之的是使用新的Composition API的`modelValue`和`update:modelValue`来实现双向绑定。这种方式更加灵活,可以更好地适应各种复杂的场景。在Vue3,通过创建一个自定义的组合函数来处理双向绑定,结合`ref`和`emit`,可以实现对数据的读取和更新。 Vue3双向绑定还引入了Proxy代理对象作为数据劫持的实现机制,相比Vue2Object.definePropertyProxy可以提供更好的性能和更灵活的操作。Proxy对象可以对整个对象进行变动的捕获和处理,所以能够更细粒度地监听到数据的变化。 总结来说,Vue3双向绑定相比Vue2更加灵活,底层实现也更高效。Vue3双向绑定通过Composition API的`modelValue`和`update:modelValue`来实现,采用Proxy代理对象进行数据劫持,能够更好地满足复杂场景下的需求,并且具有更好的性能表现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北城笑笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值