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實現一個雙向綁定。
若有不嚴謹或者錯誤的地方,望大佬們指出~