简介:Object.defineProperty大家都知道,是vue2中双向数据绑定的原理,它是 JavaScript 中一个强大且常用的方法,用于定义对象属性,允许我们精确地控制属性的行为,包括读取、写入和删除等操作;
而Proxy是vue3中双向数据绑定的原理,是ES6中一种用于创建代理对象的特殊对象,它允许我们拦截并自定义目标对象的操作,例如属性访问、赋值、函数调用等。Proxy提供了一种机制,可以在目标对象上设置拦截器,从而拦截对目标对象的操作。
一、Object.defineProperty
1、Object.defineProperty是一个用于定义或修改对象属性的方法,可以精确地控制属性的行为,例如可写性、可枚举性和可配置性;在Object.defineProperty 方法中,有三个必需的参数和一个可选的第四参数。
- obj (必需):要定义属性的对象。可以是任何 JavaScript 对象。
- prop (必需):要定义或修改的属性的名称。可以是一个字符串,表示属性的名称。
- 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、**注意事项
- get 和set 函数,不会同时被触发,它们根据属性的读取或设置操作来决定调用哪个函数;
- 该方法按照调用顺序,从上到下依次执行,就是有更新就只运行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):拦截属性的删除操作
- ......