0x000 概述
代理嘛,就是請代理人代替自己做某件事,但是和自己不一樣的是代理人可以有自己的行爲,甚至可以做出和預期相違背的行爲。
0x001 栗子
聲明一個普通對象origin
,他有一個屬性name
let origin={
name: 'origin'
}
聲明一個代理對象
let proxy=new Proxy(origin, {
get: (target, key)=>target[key]+" from proxy",
set: (target, key, value)=>target[key]="set by proxy "+value
})
此時輸出origin
和proxy
,可以發現,proxy
擁有和origin
一樣的name
屬性
console.log(origin) // {name: 'origin'}
console.log(proxy) // Proxy {name: 'origin'}
爲origin
添加age
屬性,再輸出,可以發現,origin
和proxy
都擁有了age
屬性
origin.age=1
console.log(origin) // {name: 'origin', age: '1'}
console.log(proxy) // Proxy {name: 'origin', age '1'}
那就是代理嗎,當然不是,我們嘗試爲proxy
添加屬性
proxy.x=1
console.log(origin) // {name: 'origin', age: '1', x:'set by proxy 1'}
console.log(proxy) // Proxy {name: 'origin', age '1'}
可以發現,雖然origin
和proxy
都擁有了x
屬性,但是並不是我們賦值的1
,而是多了set by proxy
幾個字符串,很明顯,這裏是執行了初始化proxy
時傳入的第二個對象的set
方法
那如果我們get
呢
console.log(proxy.x) // set by proxy 1
console.log(proxy.x) // set by proxy 1 from proxy
現在很清楚了,proxy
就是origin
的代理,所有在proxy
上的操作都會同步到origin
上,而對origin
的操作卻不會同步到proxy
上,而且proxy
還有自己的行爲。
可以這麼想,proxy
就是origin
的祕書,所有的事務處理都要提交給祕書,祕書有自己的辦事準則,可以直接提交給老闆,也可以拒絕提交,或者添加一些其他的行爲再提交。那這個祕書到底能代理老闆做哪些事呢?
0x002 陷阱
-
語法
let p = new Proxy(target, handler);
初始化一個代理需要有兩個參數
-
target
:代理目標 -
handle
:陷阱,是一個對象,我們的操作就像一隻逃跑的動物,如果獵人在所有可以逃跑的路上全部放滿了陷阱,那我們總是會落入一起一個的。本質就是一個對象,鍵描述我們的操作,值是函數,描述我們的行爲,一共有13
種陷阱。
0x003 set
:設置屬性
-
語法:
set(target, key, value)
-
target
: 代理對象 - `key: 設置的屬性
-
value
: 設置的屬性值
-
-
栗子:
let origin={} let proxy=new Proxy(origin,{ set:(target, key, value)=>{ if(value>5)target[key]=value+10000 } }) proxy.x=1 proxy.y=10 console.log(proxy) // Proxy {y: 10010} console.log(origin) // {y: 10010}
- 說明:
上面我們放置了一個set
陷阱,當我們做set
操作的時候,就會被捕捉到,我們判斷value
是否大於5
,如果不大於5
我們就不會做任何東西,但是如果大於5
,就會給做賦值操作,並且還將他加上了10000
。上面的栗子就相當於一個攔截器了。
0x004 get
:訪問屬性
-
語法:
get(target, key)
-
target
: 代理對象 - `key: 訪問的屬性
-
-
栗子:
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ get:(target, key)=>{ if(key==='x')return 'no' return target[key] } }) console.log(proxy.x) // 'no' console.log(proxy.y) // 2
0x005 deleteProperty
:刪除屬性
-
語法:
deleteProperty(target, key)
-
target
: 代理對象 - `key: 要刪除的屬性
-
-
栗子:
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ deleteProperty:(target, key)=>{ if(key==='x')return delete target[key] } }) delete proxy.x delete proxy.y console.log(proxy) // {x:1}
0x006 has
:判斷是否包含某屬性
-
語法:
has(target, key)
-
target
: 代理對象 - `key: 要判斷的屬性
-
-
栗子:
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ has:(target, key)=>{ if(key==='x')return false return true } }) console.log('x' in proxy) // false console.log('y' in proxy) // true
0x007 ownKeys
:獲取自身屬性值
-
語法:
ownKeys(target)
-
target
: 代理對象
-
-
栗子:
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ ownKeys:(target)=>{ return ['y'] } }) console.log(Object.getOwnPropertyNames(proxy)) // ['y']
0x008 getPrototypeOf
:獲取prototype
-
語法:
getPrototypeOf(target)
-
target
: 代理對象
-
-
栗子
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ getPrototypeOf:(target)=>{ return null } }) console.log(Object.getPrototypeOf(p)) // null
0x009 setPrototypeOf
:設置prototype
-
語法:
setPrototypeOf(target, prototype)
-
target
: 代理對象 -
prototype
: 要設置的prototype
-
-
栗子
let origin={ x:1, y:2 } let proxy=new Proxy(origin,{ setPrototypeOf:(target, prototype)=>{ throw 'no' } }) Object.setPrototypeOf(proxy, {}) // Uncaught no
0x010 defineProperty
:設置屬性描述
-
語法:
defineProperty(target, prop, descriptor)
-
target
: 代理對象 -
prop
: 要設置描述的屬性 -
descriptor
: 描述
-
-
栗子
let origin={} let proxy=new Proxy(origin,{ defineProperty:(target, prop, descriptor)=>{ throw 'no' } }) Object.defineProperty(proxy, 'x', {configurable: true}) // Uncaught no
0x011 getOwnPropertyDescriptor
:獲取自身屬性描述
-
語法:
getOwnPropertyDescriptor(target, prop)
-
target
: 代理對象 -
prop
: 獲取描述的屬性
-
-
栗子
let origin={} let proxy=new Proxy(origin,{ getOwnPropertyDescriptor:(target, prop)=>{ throw 'no' } }) Object.getOwnPropertyDescriptor(proxy, 'x') // Uncaught no
0x012 isExtensible
:判斷是否可擴展
-
語法:
isExtensible(target)
-
target
: 代理對象
-
-
栗子
let origin={} let proxy=new Proxy(origin,{ isExtensible:(target)=>{ return false } }) console.log(Object.isExtensible(proxy)); // false
0x013 preventExtensions
:阻止擴展
-
語法:
preventExtensions(target)
-
target
: 代理對象
-
-
栗子:
let origin={} let proxy=new Proxy(origin,{ preventExtensions:(target)=>{ return false; } }) console.log(Object.preventExtensions(proxy)); // Uncaught TypeError: 'preventExtensions' on proxy: trap returned falsish
0x014 construct
:構造
-
語法:
construct(target, argumentsList, newTarget)
-
target
: 代理對象 -
argumentsList
: 參數列表 -
newTarget
: 新對象
-
-
栗子:
let Origin=function(){} let OriginProxy=new Proxy(Origin,{ construct: function(target, argumentsList, newTarget) { throw 'error' } }) new OriginProxy() // Uncaught error
0x015 apply
:調用
-
語法:
apply(target, thisArg, argumentsList)
-
target
: 代理對象 -
thisArg
: 上下文 -
argumentsList
: 參數列表
-
-
栗子:
let origin=function(){} let proxy=new Proxy(origin,{ apply: function(target, thisArg, argumentsList) { throw 'error' } }) origin() // Uncaught error