认识Proxy
可以把Proxy看作是一个拦截器,可以对目标对象的访问进行过滤和改写。proxy实例可以拦截对象的属性读取、赋值、删除、通过definedProperty定义等操作外,还可以拦截到对象被当作方法调用还是构造函数使用等操作。那Proxy具体怎么用的呢?
Proxy的用法
通过Proxy来监测对象的赋值和读取
入门例子:给目标对象添加属性并赋值
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey} value: ${target[propKey]}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey} value: ${value}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
obj.count = 1
++obj.count
//setting count value: 1!
//getting count value: 1!
//setting count value: 2!
Proxy的特点
new Proxy(第一个参数, 第二个参数),第一个参数为目标对象,第二个参数为操作对象的行为的对象。
Proxy构造函数的第一个参数为目标对象,和new出来的Proxy实例是同一个对象,但要注意只有修改Proxy实例值才会触发对应的拦截的方法:
var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"
Proxy实例也可以做为其他对象的原型对象:
var proxy = new Proxy({}, {
get: function(target, propKey) {
return 35;
}
});
let obj = Object.create(proxy);
obj.time // 35
可以设置多个拦截操作,例如:拦截对象作为方法使用、作为构造函数使用、作为对象操作属性等操作,可以在函数中return指定值:
var handler = {
get: function(target, name) {
if (name === 'prototype') {
return Object.prototype;
}
return 'Hello, ' + name;
},
apply: function(target, thisBinding, args) {
return args[0];
},
construct: function(target, args) {
return {value: args[1]};
}
};
var fproxy = new Proxy(function(x, y) {
return x + y;
}, handler);
fproxy(1, 2) // 1
new fproxy(1, 2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo === "Hello, foo" // true
触发Proxy实例set的情况和触发Proxy实例get的情况:
- 触发Proxy实例set的情况:给实例添加属性或对已存在属性进行重新赋值时,无论属性的值是什么类型都会触发set。
- 触发Proxy实例get的情况:读取Proxy实例中的属性时(无论属性是否已经存在)、除了以上触发set的方法,其他赋值行为都会触发get(具体见下面例子各种赋值情况)。
var data = {
odata: {
name: 'odata',
age: '21'
},
arr: [{
name: 'youyi',
age: '24'
}],
name: 'bb'
}
var obsever = new Proxy(data, {
get: function (target, propKey, receiver) {
console.log('get:', target[propKey])
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log('set:', value)
return Reflect.set(target, propKey, value, receiver);
}
})
以上的结果:
赋值却触发proxy实例get方法的情况
1、对proxy实例中的数组进行操作:
2、对proxy实例中的对象的属性进行操作:
赋值触发proxy实例set方法:修改proxy实例的属性的整个值或新增一个属性并赋值时
1、修改proxy实例的数组类型属性
2、修改proxy实例的对象类型属性
Proxy的应用场景
- 实现类似Promise链式调用
var pipe = (function () {
return function (value) {
var funcStack = [];
var oproxy = new Proxy({} , {
get : function (pipeObject, fnName) {
if (fnName === 'get') {
return funcStack.reduce(function (val, fn) {
return fn(val);
},value);
}
funcStack.push(window[fnName]);
return oproxy;
}
});
return oproxy;
}
}());
var double = n => n * 2;
var pow = n => n * n;
var reverseInt = n => n.toString().split("").reverse().join("") | 0;
pipe(3).double.pow.reverseInt.get; // 63
- 利用get拦截返回函数,实现web客户端
const service = createWebService('http://example.com/data');
service.employees().then(json => {
const employees = JSON.parse(json);
// ···
});
function createWebService(baseUrl) {
return new Proxy({}, {
get(target, propKey, receiver) {
return () => httpGet(baseUrl + '/' + propKey);
}
});
}
- 实现类似vue中的响应式
defineProperty vs proxy
参考资料:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。