你好。核介是。
最近(2022/10/20),梦美做了一个小测验。
在阅读 Yumemi 的文章时,我发现了一个名为 Proxy 的对象。
正如文章标题所说,“已分配但未分配”,它是一个神秘的物体。Proxy到底是谁?
在 Yumemi 的测验示例中山元太郎断然拒绝改名隆史例如,
其实Proxy有将数千行代码变成几行代码的魔法我也有
这次想介绍一下JavaScript中Proxy的神奇力量。
本来Proxy是一个难点的内容,但是和setTimeout一样,我想让初学者尽可能容易理解。我认为。
什么是代理?
简单的说,对象可以改造事物。
我将引用 Yumemi 的文章的例子。
const user = new Proxy(obj, { set: (target) => { target.name = "やめ太郎"; return true; } })
// 元のオブジェクト
const obj = { name: "" }
// Proxyオブジェクトを生成
const user = new Proxy(obj, { set: (target) => { target.name = "やめ太郎"; return true; } })
user.name = "たかし"
console.log(user.name)
// -> "やめ太郎"
console.log(obj.name)
// -> "やめ太郎"
在此示例中,即使您尝试将用户名更改为“Takashi”,如user.name = "たかし",也会被强制更改为“Yametaro”。
确切地对象user 被Proxy 改造我被迫
然后究竟什么是魔法改造?这就是它的感觉。
在那之前,“代理”到底是什么意思?是不是?
正确答案是“副“就是这个意思。
您可能经常听说过“代理服务器”这个词。
充当客户端和后端服务器(如果有)之间的中介的“代理”服务器。
(https://cybersecurity-jp.com/column/32171引用自)
Proxy 也代表.
看看上面 Yumemi 的代码示例。
// 元のオブジェクト
const obj = { name: "" }
// Proxyオブジェクトを生成
const user = new Proxy(obj, { set: (target) => { target.name = "やめ太郎"; return true; } })
在此示例中,Proxy 充当 target.name = "やめ太郎";,而 setter 为 obj 工作。
然后究竟什么是魔法改造?这就是它的感觉。
分辨率不是在逐渐提高吗?
现在回到“代理服务器”主题。更详细地考虑代理服务器的角色。
在客户端和后端服务器之间中继的“代理”服务器
代理服务器中继。
即使你说接力,你是根据什么来做的?是吗?
例如,当客户端发送“给我页面信息”的请求时,它会向后端服务器发送请求以获取页面信息。
同样,当后端返回页面信息时,它会将页面信息返回给客户端。
Proxy也是如此.在此示例中,
Proxy充当target.name = "やめ太郎";,而 setter 为obj工作。就像“当你做〇〇时,做〇〇”这样的表达。
这是魔法改造的真相是。
Proxy定义为“当〇〇时做〇〇”,作为目标对象的代理这是。
在之前 Yumemi 的代码示例中,它是一个 setter,你甚至可以在 getter 和函数执行中定义任何你想要的东西!const user = new Proxy({ name: "" }, { get: () => "やめ太郎" })这也是 Yumemi 文章中的一个代码示例。
在这个例子中,getter 被神奇地改造了,当getter 工作时,它是返回"やめ太郎"的代理。代理魔法
我将向您展示
Proxy的力量。您的站点具有以下实现来向后端 API 发出请求。
// 各 API へアクセスするためのパスを定義 const apiPathList = { articles: '/api/articles', users: '/api/users', // ...いっぱい } // 各 API へアクセスするためのオブジェクトを定義 const myClient = { fetchArticles(queryParams) { return new Promise((resolve, reject) => { // { page: 1 } などのオブジェクトを page=1 のようなクエリパラメータに変換 const queryStr = (new URLSearchParams(queryParams)).toString(); fetch(`${apiPathList.articles}?${queryStr}`) .then(res => res.json()) .then(resolve) .catch(reject); }) } fetchUsers(queryParams) { // ... } // API のパスごとに関数を用意 // ... } // API へアクセスする時 const artcles = await myClient.fetchArticles({ page: 1 });后端有几个API,为每个API创建一个请求函数。
但是随着服务的扩展,后端变成了微服务,API的数量稳步增加。
随着 API 数量的增加,访问每个 API 的 URL 定义和请求函数也必须增加。在这里使用
Proxy来做一些魔术。const apiClient = {}; // キャメルケースを小文字にしてスラッシュに変更する関数 // 例: fetchApiArticles -> fetch/api/articles const convertCamelCaseToLowerCaseSlash = str => { return str .split(/(?=[A-Z])/) .join('/') .toLowerCase(); } // Proxy でゲッターを魔改造して、 fetch する関数を返すようにします const handler = { // prop には、関数名が入ります // myClient.fetchApiArticles だったら prop は 'fetchApiArticles' になります // target と receiver は使いません get(_target, prop, _receiver) { return queryParams => new Promise((resolve, reject) => { if (prop.indexOf('fetch') !== 0) { reject('プロパティ名の先頭は「fetch」をつけてください'); return; } // { page: 1 } などのオブジェクトを page=1 のようなクエリパラメータに変換 const queryStr = queryParams ? `?${new URLSearchParams(queryParams).toString()}` : ''; // convertCamelCaseToSlash の結果が fetch/api/articles のようになるので、先頭の fetch は削除 const requestUrl = convertCamelCaseToLowerCaseSlash(prop).replace('fetch', ''); fetch(`${requestUrl}${queryStr}`) .then(data => data.json()) .then(resolve) .catch(reject); }); }, }; const myClient = new Proxy(apiClient, handler); // 関数は定義されていないが /api/articles?page=1 でリクエストされる!! const articles = await myClient.fetchApiArticles({ page: 1 }); // 関数は定義されていないが /api/users?page=1 でリクエストされる!! const users = await myClient.fetchApiUsers({ page: 1 }); // 「プロパティ名の先頭は「fetch」をつけてください」 のエラーが出る const response = await myClient.hoge();即使没有定义像
myClient.fetchApiArticles和myClient.fetchApiUsers这样的函数,预期的请求仍然会飞! !和,即使后端API数量增加也无需修改.
例如,假设添加了一个新的 API,如/api/search。
只需使用myClient.fetchApiSearch即可完成是。此代码根据某些规则构造请求的 URL。
规则如下。
- 将“fetch”添加到属性名称的开头。
- 属性名称的驼峰式大小写照原样成为请求路径。
- 例如
fetchHogeFuga被转换为/hoge/fuga的请求路径。虽然在代码示例中是
Proxy,但您可以通过修改handler来进一步扩展功能。
例如,如果要更改请求目的地的域名,或者更改请求方式。// GET でリクエスト myClient.fetchGetApiArticles(); // hoge.com のような別ドメインにリクエスト myClient.fetchHogeDomainApiArticles();如果您为每个 API 的每个函数创建了一个测试用例,您将需要测试每个函数,但是在这个
Proxy示例中,预期的请求 URL 是基于纯属性名称发出的。既然可以得到确认,测试用例的数量也可以减少。这样
Proxy可用于减少相当数量的代码.何时使用代理
老实说,我什么都能做,所以有一些地方我可以提出想法,但关键是对象扩展我猜。
诸如
Vue和MobX之类的库扩展了您通过Proxy传递给组件的数据。
检测对象更改并仅呈现具有数据依赖关系的组件,使用Proxy检测。
它可能用于“当对某个对象进行更改时我想做〇〇!”的情况下使用它。另外,对不起我的例子,但是我已经使用
Proxy对WebWorker进行线程管理和处理访问WebWorker中的主线程的DOM。
WebWorker的线程管理例如是将WebWorker要处理的任务放入队列中,当某个线程中的处理完成后,如果队列中有任务,则继续被执行,如果没有,线程将被终止。就像。Proxy当管理Proxy包裹的线程状态的对象发生变化时,会进行管理线程的处理,如“队列中有任务则继续执行,没有则终止线程” .后者,“处理访问
WebWorker内的主线程的DOM”,在下面的文章中简要提及。
Ruby 在这方面特别强,但是
Proxy元编程这也是一个叫
作为一个完全题外话,如果有人正在研究 Ruby,我推荐这本书“Metaprogramming Ruby”。
我读了这本书,并在 Ruby 工程师认证考试中获得金牌!微笑
(如果你从这里买一本书,我会高兴地哭泣!!)
让我们一直使用代理?
“
Proxy方便!尽快用吧!”
不好是。
好吧,说不可能太多了,但我不建议这样做。
不推荐它有几个原因。
第一个原因没有人可以阅读代码这是为了
代理魔法这是一个使用Proxy的代码示例,但老实说,它一定很难阅读代码。Proxy本身就有它的特殊性,还有一个潜规则就是“这个属性名一定要写”。
我想我自己写了Proxy的处理,几个月后就看不懂了?其他,与 TypeScript 不兼容是。
正如您在Proxy实现中看到的那样,通常存在难以定义类型的情况。首先,
Proxy动态寻求自由,而 TypeScript 静态寻求严格。
这不是狗和猴子的关系,但我认为这是一个哲学矛盾。获得强大的力量是有代价的。
在认识到缺点之后,让我们使用Proxy。在最后
怎么样?如果您能以某种方式理解
Proxy,我会很高兴!如果你更深入地研究 JavaScript,你会发现新的东西。
例如,setTimeout不仅仅是一个在指定时间运行的函数。
如果描述有任何错误,请告诉我!
以后我会继续写文章,所以如果你愿意推特如果你关注我,我会通知你文章发布!
谢谢你读到这里!
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308632231.html