ES6系列之Proxy
前言
前幾天模擬實現(xiàn)了 MobX 的兩個函數(shù) —— 手寫實現(xiàn) MobX 的 observable 和 autorun 方法,其中用到了 Proxy,所以打算再對 Proxy 深入了解一下,做個筆記。
包括以前的ES6系列文,加上這篇應(yīng)該差不多了一個系列完結(jié)了。
ES6系列之let和const與var的區(qū)別
ES6系列之變量的解構(gòu)賦值
ES6系列之箭頭函數(shù)全解析
ES6系列之一文徹底弄懂Iterator
ES6系列之箭頭函數(shù)全解析
ES6系列之Generator生成器全解析
ES6 系列之 Promise 題合集
ES6 系列之手寫 Promise
Proxy 是什么
Proxy 對象用于創(chuàng)建一個對象的代理,從而實現(xiàn)基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)??梢岳斫獬?,在目標對象之前架設(shè)一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。
const p = new Proxy(target, handler)
target: 使用 Proxy 包裝的目標對象(可以是任何類型的 JavaScript 對象,包括原生數(shù)組,函數(shù),甚至另一個代理)。
handler: 一個通常以函數(shù)作為屬性的對象,用來定制攔截行為。
在支持 Proxy 的瀏覽器環(huán)境中,Proxy 是一個全局對象,可以直接使用。Proxy(target, handler)
是一個構(gòu)造函數(shù),target
是被代理的對象,最終返回一個代理對象。
為什么需要 Proxy
學(xué)習(xí)一樣?xùn)|西之前我們先要想想為什么需要它,在我看來,一般幾種情況。
被代理的對象不想直接被訪問
控制和修改被代理對象的行為(調(diào)用屬性、屬性賦值、方法調(diào)用等等),使之可以進行訪問控制和增加功能。
API
API 概覽如下:
get(target, propKey, receiver):攔截對象屬性的讀取,比如 proxy.foo 和 proxy['foo'] 。
set(target, propKey, value, receiver):攔截對象屬性的設(shè)置,比如 proxy.foo = v 或 proxy['foo'] = v ,返回一個布爾值。
has(target, propKey):攔截 propKey in proxy 的操作,返回一個布爾值。
deleteProperty(target, propKey):攔截 delete proxy[propKey]的操作,返回一個布爾值。
ownKeys(target):攔截 Object.getOwnPropertyNames(proxy) 、 Object.getOwnPropertySymbols(proxy) 、 Object.keys(proxy) 、 for...in 循環(huán),返回一個數(shù)組。該方法返回目標對象所有自身的屬性的屬性名,而 Object.keys() 的返回結(jié)果僅包括目標對象自身的可遍歷屬性。
getOwnPropertyDescriptor(target, propKey):攔截 Object.getOwnPropertyDescriptor(proxy, propKey) ,返回屬性的描述對象。
defineProperty(target, propKey, propDesc):攔截 Object.defineProperty(proxy, propKey, propDesc) 、
Object.defineProperties(proxy, propDescs),返回一個布爾值。
preventExtensions(target):攔截 Object.preventExtensions(proxy) ,返回一個布爾值。
getPrototypeOf(target):攔截 Object.getPrototypeOf(proxy),返回一個對象 。
isExtensible(target):攔截 Object.isExtensible(proxy) ,返回一個布爾值。
setPrototypeOf(target, proto):攔截 Object.setPrototypeOf(proxy, proto) ,返回一個布爾值。如果目標對象是函數(shù),那么還有兩種額外操作可以攔截。
apply(target, object, args):攔截 Proxy 實例作為函數(shù)調(diào)用的操作,比如 proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)`。
construct(target, args):攔截 Proxy 實例作為構(gòu)造函數(shù)調(diào)用的操作,比如 new proxy(...args) 。
最常用的方法就是get
和set
例子
get

運行,打印臺輸出:
獲取名字/性別
jacky
在獲取name
屬性是先進入get
方法,在get
方法里面打印了獲取名字/性別
,然后通過Reflect.get(target, key)
的返回值拿到屬性值,相當(dāng)于target[key]
set

運行輸出:
獲取名字/性別
強行設(shè)置 monkey
設(shè)置proxy.name = 'monkey',這是修改屬性的值,則會觸發(fā)到set方法, 然后我們強行更改設(shè)置的值再返回,達到攔截對象屬性的設(shè)置的目的。
Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API。
Reflect.get(target, name, receiver) :查找并返回target對象的name屬性,如果沒有該屬性,則返回undefined。
Reflect.set(target, name, value, receiver) :設(shè)置target對象的name屬性等于value。
this 指向
proxy 會改變 target 中的 this 指向,一旦 Proxy 代理了 target,target 內(nèi)部的 this 則指向了 Proxy 代理

運行代碼,會發(fā)現(xiàn)報錯,提示TypeError: proxy.getDate is not a function
,即 this 不是 Date 對象的實例,這時需要我們手動綁定原始對象即可解決:

了解更多,請點擊:https://www.bilibili.com/video/BV13a4y1n7tS/
作者:JackySummer
鏈接:https://juejin.cn/post/6913411859559219213
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。