来源:https://blog.logrocket.com,作者:Eslam Hefnawy Follow

元编程是一种强大的技术,使你能够编写可以创建其他程序的程序。ES6借助代理和许多类似功能,使在JavaScript中利用元编程变得更加容易。ES6 Proxy(代理) 有助于重新定义对象的基本操作,从而为各种可能性打开了大门。

本指南可以帮助您理解为什么ES6代理如此之好,尤其是对于元编程而言。本文你将看到:

  • 什么是ES6代理
  • 如何以及何时实施代理
  • 如何使用ES6代理执行访问控制,数据绑定和缓存
  • ES6代理不是性能密集型任务的理想选择

先决条件和结果

本教程主要针对有JavaScript经验的开发人员,至少要熟悉ES6代理的概念。如果你已经对代理作为一种设计模式有了牢固的理解,那么这些知识应该可以转化为现实。

阅读本指南后,你应该能够:

  • 了解什么是ES6代理,如何实现以及何时使用它
  • 使用ES6代理进行访问控制,缓存和数据绑定

ES6代理剖析:目标(Target),处理程序(handler)和陷阱(trap)

从根本上来说,代理是指某件事或某人成为其他事物的替代品,所以不管是什么东西,都要经过替代品才能达到真正的交易。ES6代理的工作原理也是如此。

为了有效地实现和使用ES6代理,你必须了解三个关键术语:

  1. Target——代理人所替代的真正的交易,目标是站在代理背后的东西。这可以是任何对象。
  2. Handler——一个包含所有代理的陷阱逻辑的对象。
  3. Trap——与操作系统中的陷阱类似,此上下文中的陷阱是以某种方式提供对对象的访问的方法(可理解为拦截行为)。

综上所述,下面是最简单的实现,如果使用ES6代理,对象中不存在给定的属性,则可以返回不同的内容。

const target = {someProp: 1}

const handler = {get: function(target, key) {return key in target ?      target[key] :'Doesn't exist!';  }}const proxy = new Proxy(target, handler);console.log(proxy.someProp) // 1console.log(proxy.someOtherProp) // Doesn't exist!

ES6代理是一项强大的功能,可促进JavaScript中对象的虚拟化。

数据绑定:同步多个对象

由于数据绑定的复杂性,它通常很难实现。ES6代理实现双向数据绑定的应用可以在JavaScript的MVC库中看到,在这些库中,当DOM发生变化时,对象会被修改。

简而言之,数据绑定是一种将多个数据源绑定在一起以使其同步的技术。

假设存在一个名为 username 的 。

<input type="text" id="username" /> 

假设你要使此输入的值与对象的属性保持同步。

const inputState = {id: 'username',value: ''}

当输入的值发生变化时,通过监听输入的变化事件,然后更新 inputState 的值,修改 inputState 是相当容易的。然而,反过来,在 inputState 被修改时更新输入,则相当困难。

ES6代理可以在这种情况下提供帮助。

const input = document.querySelector('#username')const handler = {set: function(target, key, value) {if (target.id && key === 'username') {      target[key] = value;document.querySelector(`#${target.id}`)        .value = value;return true    }return false  }}

const proxy = new Proxy(inputState, handler)proxy.value = 'John Doe'console.log(proxy.value, input.value)// 双方都将印有“ John Doe”

这样,当 inputState 更改时,input 将反映已进行的更改。结合侦听 change 事件,这将生成 inputinputState 的简单双向数据绑定。

虽然这是一个有效的用例,但通常不建议这样做。以后再说。

缓存:提高代码性能

缓存是一个古老的概念,它允许非常复杂和大型的应用程序保持相对的性能。缓存是存储某些数据的过程,以便在请求时可以更快地提供数据。缓存并不永久地存储任何数据。缓存失效是保证缓存新鲜的过程。这是开发人员共同的苦恼。正如Phil Karlton所说:"计算机科学中只有两件难事:缓存无效和给事物命名。"

ES6代理使缓存更加容易。例如,如果你要检查对象中是否存在某些东西,它将首先检查缓存并返回数据,或者如果不存在则进行其他操作以获取该数据。

假设你需要进行很多API调用才能获取特定信息并对其进行处理。

const getScoreboad = (player) => {  fetch('some-api-url')    .then((scoreboard) => {// 用记分牌做点什么  })}

这就意味着,每当需要一个球员的记分牌时,就必须进行一次新的调用。相反,你可以在第一次请求时缓存记分牌,随后的请求可以从缓存中获取。

const cache = {'John': ['55', '99']}const handler = {get: function(target, player) {if(target[player] {return target[player]  } else {    fetch('some-api-url')      .then(scoreboard => {        target[player] = scoreboardreturn scoreboard      })    }  }}const proxy = new Proxy(cache, handler)// 访问缓存并使用记分牌做一些事情

这样,仅当缓存中不包含玩家的记分牌时,才会进行API调用。

访问控制:控制进出对象的内容

最简单的用例是访问控制,ES6代理的大部分内容都属于访问控制。

让我们探索使用E6代理的访问控制的一些实际应用。

1. 验证

ES6代理最直观的用例之一是验证对象内部的内容,以确保对象中的数据尽可能准确。例如,如果你想强制执行产品描述的最大字符数,可以这样做。

const productDescs = {}const handler = {set: function(target, key, value) {if(value.length > 150) {      value = value.substring(0, 150)    }    target[key] = value  }}const proxy = new Proxy(productDescs, handler)

现在,即使你添加的描述超过150个字符,也会被删减并添加。

2. 提供对象的只读视图

有时候你可能要确保不以任何方式修改对象,并且只能将其用于读取目的。JavaScript提供了 Object.freeze() 来执行此操作,但是使用代理时,该行为更可自定义。

const importantData = {name: 'John Doe',age: 42}

const handler = {set: 'Read-Only',defineProperty: 'Read-Only',deleteProperty: 'Read-Only',preventExtensions: 'Read-Only',setPrototypeOf: 'Read-Only'}

const proxy = new Proxy(importantData, handler)

现在,当你尝试以任何方式更改对象时,你只会收到一个字符串,表示只读。否则,你可能会引发错误以指示该对象是只读的。

3. 私有属性

JavaScript本身并没有私有属性,除了闭包。当 Symbol 数据类型被引入时,它被用来模仿私有属性。但随着Object.getOwnPropertySymbols 方法的引入,它被抛弃了。ES6代理并不是一个完美的解决方案,但在紧要关头它们可以完成任务。

一种常见的约定是通过在名称前加上下划线来标识私有属性,这个约定允许你使用ES6代理。

const object = {_privateProp: 42}

const handler = {has: function(target, key) {return !(key.startsWith('_') && key in target)  },get: function(target, key, receiver) {return key in receiver ? target[key] : undefined  }}

const proxy = new Proxy(object, handler)proxy._privateProp // undefined

添加 ownKeysdeleteProperty 会让这个实现更接近于真正的私有属性。然后,你仍然可以在开发者控制台中查看代理对象。如果你的用例与上面的实现一致,它仍然适用。

为何以及何时使用代理

ES6代理并不是性能密集型任务的理想选择。这就是为什么进行必要的测试是至关重要的。代理可以在任何预期对象的地方使用,代理只需几行代码就能提供复杂的功能,这使它成为元编程的理想功能。

代理通常与另一个称为Reflect的元编程功能一起使用。


前端大礼包新增课程了?

新增课程《再学JavaScript ES(5-10)全版本语法大全》,学习当下和未来大热技术!公众号中回复关键字:“前端大礼包”即可获取,不定期新增新课程,新增课程都会通知大家。


近期文章

DOM API中append和appendChild的三个不同点

在JavaScript中使用Spread运算符的8种方法

你知道Object.entries(),但你还知道有Object.fromEntries()吗?

Vue技巧 | 在Vue3中使元素在滚动视图时淡入

实战|如何使用JavaScript访问设备前后摄像头

仅3行核心CSS代码的rate评分组件

使用JavaScript的padStart和padEnd格式化字符串

Vue 3教程(适用于Vue 2用户)

JavaScript vs Dart  两者之间的比较

不要过度使用React.useCallback()

HTML页面生成器:使用JavaScript和Node创建CLI

React.js和Vue.js的语法并列比较

从零开始使用JavaScript制作自己的命令行(CLI工具)

Vue.js中编写更好的v-for循环的6种技巧

如果对你有帮助,还可以在看、留言、转发,这是对作者最大的帮助。

编写有效用例电子版_JavaScript ES6代理的实际用例相关推荐

  1. 学习编写用例是开发者走向项目经理的必经之路(《编写有效用例》书评) ——“Jolt大奖精选丛书”有奖征文...

    无论在哪个一个软件工程的流程模型里,用例分析总是首当其冲的. 为什么用例分析如此重要?因为他是连接客户与开发者的纽带.客户的需求被化为用例,而开发者根据用例来决定软件的功能的.不明确甚至是错误的用例很 ...

  2. 《编写有效用例》导读书评——“Jolt大奖精选丛书”有奖征文

    我做开发的时候,曾经听过一句话:如果在一个软件公司问10个人,听说过"用例"没有?可能有9个人会说听说过. 但其中可能只有1个人知道什么是真正的"用例".那一个 ...

  3. 《编写有效用例》阅读笔记04

    随着阅读的深入我愈发得觉得<编写有效用例>是一本有价值的书. 书的第二部分的内容是 经常讨论的主题.告诉给我们在编写用例的时候我们经常会遇到的问题和遇到的误区. 首先,我们经常讨论的问题有 ...

  4. 《编写有效用例》阅读笔记05

    <编写有效用例>为我们提供了很多用例的编写技巧以及需求分析的知识,通过这些知识我们可以根据实际项目的情况运用更加娴熟的用例编写技巧来帮助我们更好的完成工作.在第一篇阅读笔记中我们就谈到了用 ...

  5. 编写有效用例笔记- 第六章 前置条件、触发事件和保证

    http://tommwq.tech/blog/2020/11/26/236 前置条件(precondition)是启动用例时必须满足的最小条件.系统要对前置条件进行检查.如果一个用例的前置条件太多, ...

  6. 关于用例需要多少文档以及业务用例等等

    整理者:张克强 缘起 @jackyrong 发了如下一条微博 敏捷中的文档该写多少合适,一直是永恒的话题,每个用例故事的设计简要卡片,用例图,序列图,类图,数据字典,简要原型图,算法补充说明,应该是必 ...

  7. java单例默认_Spring bean为什么默认是单例

    熟悉Spring开发的朋友都知道Spring提供了5种scope分别是singleton.prototype.request.session.global session. 如下图是官方文档上的截图, ...

  8. python–爬虫–模拟登录全面介绍和简例–以抓取雅卓app为例

    转载请注明出处:python–爬虫–模拟登录全面介绍和简例–以抓取雅卓app为例 我们在前面的文章中已经学习了如果使用python进行数据抓取. 但我们常常会遇到一种场景,就是想要获取的页面内容或者接 ...

  9. 编写有效用例电子版_剖析用例设计方法的使用

    今天给大家讲解的是用例设计方法的使用,在设计用例时该如何应用用例设计方法.设计出覆盖率高的测试用例呢? 场景 简介:普遍登录页面测试用例设计 分析 拿到需求,首先要做需求分析.我们看到登录界面有三个测 ...

最新文章

  1. 《使用CSLA 2019:CSLA .NET概述》原版和机译文档下载
  2. 2017-2-15从0开始前端学习笔记(HTML)-图片-表格-表单
  3. JavaScript总结(六)
  4. oracle 00371,PLS-00371: 'WEB_LOGIN_CHECK_PK.CURSORTYPE' 最多允许有一个声明
  5. Linux容器间共享内存,C++容器模板在共享内存中的使用
  6. 无惧上代信号差诟病?谷歌Pixel 7系列继续搭载三星基带芯片
  7. MySQL迁移安装_mysql数据库安装路径迁移
  8. Java之final关键字详解
  9. (转)非常完善的Log4net详细说明
  10. JAVA Web开发MySQL数据库记录浏览分页
  11. CRM客户管理系统能为企业带来什么好处?
  12. java 生成kml 文件
  13. 果园机器人作文开头_果园机器人作文
  14. 一个小小的笔顺程序,按钮太多,暂时实现了两个
  15. 托业词汇汇总(修订版)
  16. 知道Ping的最后一个返回值TTL是什么意思吗?
  17. 【Python从入门到精通】(三)Python的编码规范,标识符知多少?
  18. Maven打包自定义MANIFEST.MF键值对
  19. python hasattr函数_Python hasattr()函数
  20. python if continue的用法_Python continue语句用法实例

热门文章

  1. linux搭建压力测试,安装GTKStressTesting:对Linux系统进行压力测试变得更加容易
  2. python requests 示例_Python3中requests库学习01(常见请求示例)
  3. docker hub push_如何制作Docker镜像(image)?
  4. 不会吧不会吧!不会有人还有没有用CSDN的浏览器插件吧!
  5. 车场系统服务器内存莫名急速下降,宝德工控机在停车场监控系统的解决方案
  6. 数学专业下的计算机科学,被录取到信息与计算科学专业,这个专业什么性质,发展前景如何?...
  7. android 分享小程序,Android分享微信小程序给微信好友,封面bitmap的处理
  8. linux pid文件找不到,linux – 当’正确’时,PID文件是否仍有缺陷?
  9. python程序设计与应用第2章实验
  10. win7怎么设置开机密码_win7系统设置电脑密码的方法