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