MDN中的描述javascript
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
Proxy 对象通常用于给基本操做定义自定义行为(例如:属性查询,赋值,枚举,函数调用等)java
Proxy是ES6中原生提供的一个构造函数,Proxy字面意思是“代理”,其实它更像一种拦截器,在访问,赋值等基本操做时会先到咱们定义好的拦截方法中,根据访问的信息去执行咱们想要的操做。chrome
Proxy构造函数中接受两个参数数组
new Proxy(target, handler);
复制代码
target
参数指的是目标对象handler
指用户自定义的行为对象来看一个使用例子🌰:app
var handler = {
get (target, propkey, receiver) {
console.log('getting values');
return target[propkey] || 'value is not defined';
},
set (target, propkey, value, receiver) {
console.log('setting values');
return target[propkey] = value;
}
}
var proxy = new Proxy({}, handler);
console.log(proxy.a);
// 输出
// getting values
// value is not defined
proxy.a = 111;
// 输出
// setting values
console.log(proxy.a)
// 输出
// getting values
// 111
复制代码
上面代码定义了一个拥有 get 和 set 的代理,当咱们在访问proxy
对象中的a
时,会进入handler
中的 get 方法并执行。一样,当咱们给proxy
赋值时,亦会进入handler
中的set方法中。函数
proxy
中的get和set更为强大,不只能够监听数组下标的变化,还能够监听到对象原型属性的变化/** * proxy监听数组下标 */
var proxyArr = new Proxy([], {
get(target, propkey) {
console.log('数组下标被监听:get');
return target[propkey];
},
set(target, propkey, value) {
console.log('数组下标被监听:set');
return target[propkey] = value;
}
})
console.log(proxyArr[0]);
// 数组下标被监听:get
// undefined
proxyArr[0] = 1;
// 数组下标被监听:set
/** * proxy监听对象原型 */
var obj = {a:1};
var prototypeObj = Object.create(obj);
var proxyPrototype = new Proxy(prototypeObj, {
get(target, propkey) {
console.log('对象原型被监听:get');
return target[propkey];
},
set(target, propkey, value) {
console.log('对象原型被监听:set');
return target[propkey] = value;
}
})
console.log(proxyPrototype.a);
// 对象原型被监听:get
// 1
proxyPrototype.a = 2;
// 对象原型被监听:set
复制代码
handler
中的对象属性Proxy
不只能够用于监听数据变化,还能够监听调用函数,构造函数实例化等操做handler
对象具体的参数有13个:
get(target, propkey, receiver)
set(target, propkey, receiver)
has(target, propkey)
deleteProperty(target, propkey)
ownkeys(target)
getOwnPropertyDescriptor(target, propKey)
defineProperty(target, propkey, propDesc)
preventExtensions(target)
getPrototypeOf(target)
isExtensible(target)
setPrototypeOf(target, proto)
apply(target, object, args) // 调用函数前触发
construct(target, args) // 构造函数实例化前触发
上文说到,defineProperty
不能监听数组下标变化和对象原型的变化,Proxy
则能够支持。post
defineProperty
监听的是一个对象的属性,proxy
监听的是整个对象。测试
与defineProperty
比较proxy
的速度更快,咱们写两个测试的用例比较一下二者的速度ui
/** * defineProperty测试用例 */
var defineObj = {};
console.time('defineProperty');
for (var x = 0; x < 100000; x++) {
Object.defineProperty(defineObj, 'test_' + x, {
get() {
return value;
},
set(value) {
return defineObj['test_' + x] = value;
}
});
}
console.timeEnd('defineProperty');
/** * proxy测试用例 */
var proxy = new Proxy({}, {
get(target, propkey) {
return target[propkey];
},
set(target, propkey, value) {
return target[propkey] = value
}
});
console.time('proxy');
for (var x = 0; x < 100000; x++) {
proxy['test_' + x] = 1;
}
console.timeEnd('proxy');
复制代码
在chrome中运行proxy的速度 spa
运行defineProperty的速度
proxy
比defineProperty
占用的内存更少,咱们用上面的例子改造测试一下二者的内存占用/** * proxy 内存占用测试 */
var i = 0;
var proxy = new Proxy({}, {
get(target, propkey) {
return target[propkey];
},
set(target, propkey, value) {
return target[propkey] = value
}
});
console.log('start');
var timer = null;
timer = setInterval(function(){
if (i > 10) {
console.log('finish');
return clearTimeout(timer);
}
i++;
for (var x = 0; x < 10000; x++) {
proxy['test_' + i + '_' + x] = 1;
}
}, 1000)
/** * defineProperty 内存占用测试 */
var i = 0;
var defineObj = {};
console.log('start');
timer = setInterval(function(){
if (i > 10) {
console.log('finish');
return clearTimeout(timer);
}
for (var x = 0; x < 10000; x++) {
Object.defineProperty(defineObj, 'test_' + i + '_' + x,{
get() {
return value;
},
set(value) {
return defineObj['test_' + i + '_' + x] = value;
}
});
}
i++;
}, 1000)
复制代码
chrome 运行defineProperty
的测试用例
运行proxy
的测试用例
本节咱们了解了Proxy
中的做用和与defineProperty
相比,Proxy
的优点。
下一节就来实践一下,使用proxy实现一个双向绑定。
若有不严谨或者错误的地方,望大佬们指出~