赞
踩
用 Vue 官方文档的一句话介绍响应性:响应性是一种允许我们以声明式的方式去适应变化的编程范例。
如果我们的一个数据改变了,Vue 知道怎么去更新模板以及会更新模板的计算机属性。响应性是 Vue 用来实现UI的核心原理,在用户修改数据的时候,UI会自动更新。
Proxy是用于创建一个对象的代理,从而实现基本操作的拦截和自定义。
注意: 不是数据双向绑定,(数据双向绑定是model层和view层之间的关系)
个人理解proxy 应该是一个包装类,就是包装对象的一个方法,其实本质还是这个对象,包装完增加了一些功能而已
// target: 被 Proxy 代理的对象
// handler: 处理器的对象,设置拦截等基本操作
const p = new Proxy(target, handler)
get 方法: 用于拦截对象的读取操作 第三个参数receiver是最初被调用的对象
var original = {
a: 1,
b: 2
};
var p = new Proxy(original, {
get: function (target, property, receiver) {
delete target.b;
console.log(target, property, receiver);
return target.a
}
});
console.log(p.a);
console.log(p);
console.log(original);
set 方法: 用于拦截设置属性值的操作
const monster1 = {eyeCount: 4, abc: 90}; const handler1 = { set(obj, prop, value) { console.log(obj, prop, value, ' --------- 参数值'); if (prop === 'eyeCount' && value % 2 !== 0) { console.log('Monsters must have an even number of eyes'); } else { return Reflect.set(...arguments); } } }; const proxy1 = new Proxy(monster1, handler1); proxy1.eyeCount = 1; console.log(proxy1.eyeCount); proxy1.eyeCount = 2; console.log(proxy1.eyeCount);
deleteProperty 方法: 用于拦截对对象属性的 delete 操作。
var p = new Proxy({}, {
deleteProperty: function(target, prop) {
console.log('called: ' + prop);
return true;
}
});
delete p.a; // "called: a"
applay 方法: 用于拦截函数的调用
function sum(a, b) {
return a + b;
}
const handler = {
apply: function (target, thisArg, argumentsList) {
console.log(`${argumentsList}`);
return target(argumentsList[0], argumentsList[1]) * 10;
}
};
const proxy1 = new Proxy(sum, handler);
console.log(sum(1, 2));
console.log(proxy1(1, 2));
construct 方法: 用于拦截new 操作符
function monster1(disposition) {
this.disposition = disposition;
}
// const monster = new monster1(); 提前 new 无法触发 construct
const handler1 = {
construct(target, args) {
return new target(...args);
}
};
const proxy1 = new Proxy(monster1, handler1);
console.log(new proxy1('fierce').disposition);
getPrototypeOf 方法: 当读取代理对象的原型时,该方法就会被调用
const monster1 = {
eyeCount: 4
};
const monsterPrototype = {
eyeCount: 2
};
const handler = {
getPrototypeOf(target) {
return monsterPrototype;
}
};
const proxy1 = new Proxy(monster1, handler);
console.log(Object.getPrototypeOf(proxy1) === monsterPrototype);
console.log(Object.getPrototypeOf(proxy1).eyeCount);
has 方法: 针对 in 操作符的代理方法
const handler1 = { has(target, key) { console.log(target, key); if (key[0] === '_') { // 字符串可以通过这种方法获取到第一个字符 return false; } return key in target; } }; const monster1 = { _secret: 'easily scared', eyeCount: 4 }; const proxy1 = new Proxy(monster1, handler1); console.log('eyeCount' in proxy1); console.log('_secret' in proxy1); console.log('_secret' in monster1);
细节:
看一个例子:
var obj = {a: 1, b: 2} Object.defineProperty(obj, 'c',{ get(){ return 4 } }) // output {a: 1, b: 2} obj.c // output 4 Object.defineProperty(obj, 'c',{ get(){ return 3 } }) //output VM1139:1 Uncaught TypeError: Cannot redefine property: c // at Function.defineProperty (<anonymous>) // at <anonymous>:1:8 Reflect.defineProperty(obj, 'c', { get(){ return 3 } }) // output false
结论:
Reflect 可以通过返回值就会知道成功还是失败。 不会导致代码单线程卡住,阻塞下面代码运行
vue3底层的对象响应式的雏形是这样的,利用proxy代理,利用reflect反射(对源数据进行操作)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。