前言
在講解Proxy之前,我們有些前置知識點是必要掌握的:
- Object相關靜態函數
- Reflect相關靜態函數
簡單說明知識盲點
名稱 | 介紹 |
---|---|
Object.isExtensible() | 方法判斷一個對象是否是可擴展的(是否可以在它上面添加新的屬性) |
Object.setPrototypeOf() | 方法設置一個指定的對象的原型 ( 即, 內部[[Prototype]]屬性)到另一個對象或null |
Object.preventExtensions() | 方法讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性。 |
Object.getOwnPropertyDescriptor() | 方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性) |
Object.getPrototypeOf() | 方法返回指定對象的原型(內部[[Prototype]] 屬性的值)。 |
Reflect 是一個內置的對象,它提供攔截 JavaScript 操作的方法。這些方法與proxy handlers的方法相同。Reflect
不是一個函數對象,因此它是不可構造的。可用來替換部分Object靜態函數, 比較好的一點是__避免直接報錯__
- 其和Object.xxx類似
Vue沒有Proxy會怎么樣?
Vue問題總結
- 數組元素基本數據類型無法響應式
- 添加/刪除對象屬性很麻煩
proxy開始
- Proxy 對象用於定義基本操作的自定義行為(如屬性查找,賦值,枚舉,函數調用等)。
var proxy = new Proxy(target,handler)
參數組成
名稱 | 描述 |
---|---|
handler | 包含陷阱(traps)的占位符對象。 |
traps | 提供屬性訪問的方法。這類似於操作系統中捕獲器的概念。 |
target | 代理虛擬化的對象。它通常用作代理的存儲后端。 |
畫圖演示
陷阱API
功能分類 | API |
---|---|
操作值 | set、get |
操作屬性 | defineProperty、deleteProperty |
操作函數 | apply、construct |
原型、屬性描述符 | 見下文 |
獲取及設置
get(target, prop, receiver) {
console.log('handler.get()');
return target[prop];
},
set(obj, prop, value) {
console.log('handler.set()')
obj[prop]=value;
},
操作屬性
defineProperty(...args) {
console.log('handler.defineProperty()');
Reflect.defineProperty(...args);
},
deleteProperty(target, prop) {
console.log('handler.deleteProperty()');
return Reflect.deleteProperty(target,prop);
}
關於函數對象
apply(target, thisArg, argumentsList) {
console.log('handler.apply()',target, thisArg,argumentsList)
},
construct(target,args) {
console.log('handler.construct()');
return Reflect.construct(...args);
},
額外補充(了解)
- 另外Proxy也提供了對原型、屬性描述符的攔截
setPrototypeOf(...args) {
console.log('handler.setPrototypeOf()');
// 設置原型 prototype
return Reflect.setPrototypeOf(...args);
},
getOwnPropertyDescriptor() {
console.log('handler.getOwnPropertyDescriptor()');
// 獲取屬性描述符 -> defineProperty(obj,key,屬性描述符);
// { configurable:false } // 該屬性不能改,不能刪
},
getPrototypeOf() {
// 獲取原型對象 Object.getPrototypeOf() 觸發
// Reflect.getPrototypeOf(); // 觸發
console.log('handler.getPrototypeOf()')
},
has(o,key) { // console.log('key' in obj); 觸發
console.log('handler.has()');
return key in o;
// return Reflect.has(o,key);
},
isExtensible() {
// 判斷對象是否不可操作(C) 添加屬性 -> defineProperty
// Reflect.isExtensible 觸發
console.log('handler.isExtensible()')
},
ownKeys() {
// Reflect.ownKeys 觸發
// 獲取屬於自身非繼承的key
console.log('handler.ownKeys()')
},
preventExtensions() {
// 禁止 添加屬性
console.log('handler.preventExtensions()')
},
取消代理
-
一個對象,如果在自身對象上沒有某個屬性,比如自己不帶name屬性,但是原型鏈上有代理,就會觸發該代理get函數對於name屬性的行為
-
創建一個可取消的代理對象 {proxy,revoke}
var revocable = Proxy.revocable({}, {
get(target, name) {
return "[[" + name + "]]";
}
});
var proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke(); // 取消代理
console.log(proxy.foo); // 拋出 TypeError