Js ES6代理的实际用例

更新日期: 2020-06-01阅读: 1.3k标签: es6

元编程是一种强大的技术,使你能够编写可以创建其他程序的程序。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) // 1
console.log(proxy.someOtherProp) // Doesn't exist!

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


数据绑定:同步多个对象

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

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

假设存在一个名为 username 的 <input>。

<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 事件,这将生成 input 和 inputState 的简单双向数据绑定。

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


缓存:提高代码性能

缓存是一个古老的概念,它允许非常复杂和大型的应用程序保持相对的性能。缓存是存储某些数据的过程,以便在请求时可以更快地提供数据。缓存并不永久地存储任何数据。缓存失效是保证缓存新鲜的过程。这是开发人员共同的苦恼。正如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] = scoreboard
        return 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

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


为何以及何时使用代理

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

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

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


链接: https://www.fly63.com/article/detial/9374

es6 箭头函数的使用总结,带你深入理解js中的箭头函数

箭头函数是ES6中非常重要的性特性。它最显著的作用就是:更简短的函数,并且不绑定this,arguments等属性,它的this永远指向其上下文的 this。它最适合用于非方法函数,并且它们不能用作构造函数。

详解JavaScript模块化开发require.js

js模块化的开发并不是随心所欲的,为了便于他人的使用和交流,需要遵循一定的规范。目前,通行的js模块规范主要有两种:CommonJS和AMD

js解构赋值,关于es6中的解构赋值的用途总结

ES6中添加了一个新属性解构,允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。用途:交换变量的值、从函数返回多个值、函数参数的定义、提取JSON数据、函数参数的默认值...

ES6中let变量的特点,使用let声明总汇

ES6中let变量的特点:1.let声明变量存在块级作用域,2.let不能先使用再声明3.暂时性死区,在代码块内使用let命令声明变量之前,该变量都是不可用的,4.不允许重复声明

ES6的7个实用技巧

ES6的7个实用技巧包括:1交换元素,2 调试,3 单条语句,4 数组拼接,5 制作副本,6 命名参数,7 Async/Await结合数组解构

ES6 Decorator_js中的装饰器函数

ES6装饰器(Decorator)是一个函数,用来修改类的行为 在设计阶段可以对类和属性进行注释和修改。从本质上上讲,装饰器的最大作用是修改预定义好的逻辑,或者给各种结构添加一些元数据。

基于ES6的tinyJquery

Query作为曾经Web前端的必备利器,随着MVVM框架的兴起,如今已稍显没落。用ES6写了一个基于class简化版的jQuery,包含基础DOM操作,支持链式操作...

ES6 中的一些技巧,使你的代码更清晰,更简短,更易读!

ES6 中的一些技巧:模版字符串、块级作用域、Let、Const、块级作用域函数问题、扩展运算符、函数默认参数、解构、对象字面量和简明参数、动态属性名称、箭头函数、for … of 循环、数字字面量。

Rest/Spread 属性_探索 ES2018 和 ES2019

Rest/Spread 属性:rest操作符在对象解构中的使用。目前,该操作符仅适用于数组解构和参数定义。spread操作符在对象字面量中的使用。目前,这个操作符只能在数组字面量和函数以及方法调用中使用。

使用ES6让你的React代码提升到一个新档次

ES6使您的代码更具表现力和可读性。而且它与React完美配合!现在您已了解更多基础知识:现在是时候将你的ES6技能提升到一个新的水平!嵌套props解构、 传下所有props、props解构、作为参数的函数、列表解构

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!