摘要:然而生活并不是這樣,作為一個未成年人,總是有各種的代理人圍繞在你身邊,比如這樣學習這個時候如果調(diào)用依然是小紅,因為真心不會說謊。的基本語法如下其中是即將被代理的對象比如想要出門找小紅玩耍的,就是代理的魔法之手,用來攔截改造的行為。
前言 什么是代理?
上小學的時候,李小紅來你家叫你出去玩,第一個回應的不是你自己,是你媽:“王小明在家寫作業(yè),今天不出去!”
上中學的時候,趙二虎帶著小弟們放學在校門口等著揍你,走在前面的不是你自己,是二虎他爸:“考試沒及格還學會裝黑社會了!”拎起二虎就是一頓胖揍。
上了大學,躺在宿舍里的床上,好餓。出門買飯并交代好不要蔥蒜多放辣最后還直接端到床上的不是你自己,是快遞小哥。
這些都是代理。
什么是 JavaScript 代理?用官方的洋文來說,是 Proxy:
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
通過 Proxy 我們可以攔截并改變一個對象的幾乎所有的根本操作,包括但不限于屬性查找、賦值、枚舉、函數(shù)調(diào)用等等。
在生活中,通過代理我們可以自動屏蔽小紅的邀請、自動趕走二虎的威脅、自動買好干凈的飯端到床上。在 JavaScript 世界里,代理也可以幫你做類似的事情,接下來讓我們一起琢磨一番。
初識代理:Hello World以小學經(jīng)歷為例子,心里是喜歡小紅的,于是我們定義:
const me = { name: "小明", like: "小紅" }
這個時候如果調(diào)用 console.log(me.like),結(jié)果必然是 小紅。然而生活并不是這樣,作為一個未成年人,總是有各種的代理人圍繞在你身邊,比如這樣:
const meWithProxy = new Proxy(me, { get(target, prop) { if (prop === "like") { return "學習"; } return target[prop]; } });
這個時候如果調(diào)用 console.log(me.like) 依然是 小紅 ,因為真心不會說謊。但當我們調(diào)用 console.log(meWithProxy.like) 的時候,就會可恥的輸出 學習 ,告訴大家說我們喜歡的是 學習 。
小試牛刀:不要停止我的音樂剛才我們簡單了解了代理能夠攔截對象屬性的獲取,可以隱藏真實的屬性值而返回代理想要返回的結(jié)果,那么對于對象屬性的賦值呢?讓我們一起來看看。
假設你正在聽音樂:
const me = { name: "小明", musicPlaying: true }
此時如果我們執(zhí)行 me.musicPlaying = false 這樣就輕而易舉地停止了你的音樂,那么如果我們掛上代理人:
const meWithProxy = new Proxy(me, { set(target, prop, value) { if (prop === "musicPlaying" && value !== true) { throw Error("任何妄圖停止音樂的行為都是耍流氓!"); } target[prop] = value; } });
這時候如果我們執(zhí)行 me.musicPlaying = false,就會被毫不留情地掀了桌子:
> meWithProxy.musicPlaying = false Error: 任何妄圖停止音樂的行為都是耍流氓! at Object.set (repl:4:13) >釋放魔法:封裝全宇宙所有 RESTful API
現(xiàn)在我們已經(jīng)知道通過 Proxy 可以攔截屬性的讀寫操作,那然后呢?沒什么用?
僅僅是攔截屬性的讀寫操作,的確沒有太大的發(fā)揮空間,或許可以方便的做一些屬性賦值校驗工作等等。但是,或許你還沒有意識到一個驚人的秘密:Proxy 在攔截屬性讀寫操作時,并不在乎屬性是否真的存在!
那么,也就是說:利用 Proxy,我們可以攔截并不存在的屬性的讀取。
再進一步思考:利用 Proxy,我們可以在屬性讀取的那一瞬間,動態(tài)構(gòu)造返回結(jié)果。
然而,屬性并不局限于字符串、布爾值,屬性可以是對象、函數(shù)、任何東西。
至此,你想到了什么?
沒想到?不要緊!根據(jù)剛才的分析,讓我們一起通過下面 17 行代碼,來封裝全宇宙所有的 RESTful API !
import axios from "axios"; const api = new Proxy({}, { get(target, prop) { const method = /^[a-z]+/.exec(prop)[0]; const path = "/" + prop .substring(method.length) .replace(/([a-z])([A-Z])/g, "$1/$2") .replace(/$/g, "/$/") .toLowerCase(); return (...args) => { // <------ 返回動態(tài)構(gòu)造的函數(shù)! const url = path.replace(/$/g, () => args.shift()); const options = args.shift() || {}; console.log("Requesting: ", method, url, options); return axios({ method, url, ...options }); } } });
定義了 api 這個代理之后,我們就可以像下面這樣調(diào)用:
api.get() // GET / api.getUsers() // 獲取所有用戶 // GET /users api.getUsers$Books(42) // 獲取 ID 為 42 的用戶的所有書籍 // GET /users/42/books api.getUsers$Books(42, { params: { page: 2 } }) // 獲取 ID 為 42 的用戶的所有書籍的第二頁 // GET /users/42/books?page=2 api.postUsers({ data: { name: "小明" } }) // 創(chuàng)建名字為 小明 的用戶 // POST /users Payload { name: "小明" }
以上所有的函數(shù)都在你調(diào)用的那一瞬間,通過代理人的魔法之手動態(tài)生成,供我們隨意取用。
簡潔、優(yōu)雅,哇~ 真是太棒啦!
終極魔幻:通讀代理人的魔法秘笈到此,我們僅僅使用 Proxy 改造了對象的屬性獲取、賦值操作,而對于 Proxy 來說,只是冰山一角。
Proxy 的基本語法如下:
new Proxy(target, handler)
其中 target 是即將被代理的對象(比如:想要出門找小紅玩耍的 me),handler 就是代理的魔法之手,用來攔截、改造 target 的行為。
對于 handler 對象,我們剛才僅僅用到了 get、set 函數(shù),而實際上一共有 13 種可代理的操作:
handler.getPrototypeOf()
在讀取代理對象的原型時觸發(fā)該操作,比如在執(zhí)行 Object.getPrototypeOf(proxy) 時。
handler.setPrototypeOf()
在設置代理對象的原型時觸發(fā)該操作,比如在執(zhí)行 Object.setPrototypeOf(proxy, null) 時。
handler.isExtensible()
在判斷一個代理對象是否是可擴展時觸發(fā)該操作,比如在執(zhí)行 Object.isExtensible(proxy) 時。
handler.preventExtensions()
在讓一個代理對象不可擴展時觸發(fā)該操作,比如在執(zhí)行 Object.preventExtensions(proxy) 時。
handler.getOwnPropertyDescriptor()
在獲取代理對象某個屬性的屬性描述時觸發(fā)該操作,比如在執(zhí)行 Object.getOwnPropertyDescriptor(proxy, "foo") 時。
handler.defineProperty()
在定義代理對象某個屬性時的屬性描述時觸發(fā)該操作,比如在執(zhí)行 Object.defineProperty(proxy, "foo", {}) 時。
handler.has()
在判斷代理對象是否擁有某個屬性時觸發(fā)該操作,比如在執(zhí)行 "foo" in proxy 時。
handler.get()
在讀取代理對象的某個屬性時觸發(fā)該操作,比如在執(zhí)行 proxy.foo 時。
handler.set()
在給代理對象的某個屬性賦值時觸發(fā)該操作,比如在執(zhí)行 proxy.foo = 1 時。
handler.deleteProperty()
在刪除代理對象的某個屬性時觸發(fā)該操作,比如在執(zhí)行 delete proxy.foo 時。
handler.ownKeys()
在獲取代理對象的所有屬性鍵時觸發(fā)該操作,比如在執(zhí)行 Object.getOwnPropertyNames(proxy) 時。
handler.apply()
在調(diào)用一個目標對象為函數(shù)的代理對象時觸發(fā)該操作,比如在執(zhí)行 proxy() 時。
handler.construct()
在給一個目標對象為構(gòu)造函數(shù)的代理對象構(gòu)造實例時觸發(fā)該操作,比如在執(zhí)行new proxy() 時。
對于以上 13 種可代理的操作,還需要讀者自行研究并實踐方可踏上終極魔幻之旅。
同學,我看好你。
參考鏈接:
Proxy - JavaScript | MDN
How to use JavaScript Proxies for Fun and Profit – DailyJS – Medium
文 / 王小明
本文已由作者授權(quán)發(fā)布,版權(quán)屬于創(chuàng)宇前端。歡迎注明出處轉(zhuǎn)載本文。本文鏈接:https://knownsec-fed.com/2018...
想要訂閱更多來自知道創(chuàng)宇開發(fā)一線的分享,請搜索關注我們的微信公眾號:創(chuàng)宇前端(KnownsecFED)。歡迎留言討論,我們會盡可能回復。
歡迎點贊、收藏、留言評論、轉(zhuǎn)發(fā)分享和打賞支持我們。打賞將被完全轉(zhuǎn)交給文章作者。
感謝您的閱讀。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/97934.html
摘要:問題是這些服務都是第三方提供的,不能保證它們的響應時間,快的話美團點評分布式生成系統(tǒng)后端掘金背景在復雜分布式系統(tǒng)中,往往需要對大量的數(shù)據(jù)和消息進行唯一標識。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進階-多線程開發(fā)關鍵技術 - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請務必將下面這段話置于文章...
摘要:問題是這些服務都是第三方提供的,不能保證它們的響應時間,快的話美團點評分布式生成系統(tǒng)后端掘金背景在復雜分布式系統(tǒng)中,往往需要對大量的數(shù)據(jù)和消息進行唯一標識。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進階-多線程開發(fā)關鍵技術 - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請務必將下面這段話置于文章...
摘要:但現(xiàn)實情況是到目前為止是人民群眾集體擁有比特幣公共網(wǎng)絡,正是集體給了比特幣力量。網(wǎng)絡效應就像跑遠的火車,比特幣基于工作量證明法的永恒不變的網(wǎng)絡已經(jīng)跑的很遠了,而且?guī)缀醪豢赡鼙怀健? 全文轉(zhuǎn)載自硬幣星球翻譯:李林 校對:杜江南 英文原文: Bitcoin’s superpower: Immutability Volumne 1, Monday, Febuary 25, 2019 永恒不...
摘要:但現(xiàn)實情況是到目前為止是人民群眾集體擁有比特幣公共網(wǎng)絡,正是集體給了比特幣力量。網(wǎng)絡效應就像跑遠的火車,比特幣基于工作量證明法的永恒不變的網(wǎng)絡已經(jīng)跑的很遠了,而且?guī)缀醪豢赡鼙怀健? 全文轉(zhuǎn)載自硬幣星球翻譯:李林 校對:杜江南 英文原文:Bitcoin’s superpower: Immutability?Volumne 1, Monday, Febuary 25, 2019 永恒不變...
閱讀 3043·2021-09-03 10:33
閱讀 1270·2019-08-30 15:53
閱讀 2618·2019-08-30 15:45
閱讀 3379·2019-08-30 14:11
閱讀 527·2019-08-30 13:55
閱讀 2582·2019-08-29 15:24
閱讀 1906·2019-08-26 18:26
閱讀 3558·2019-08-26 13:41