下面是最简单的实现,如果使用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 的 ``。
假设你要使此输入的值与对象的属性保持同步。
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代理的访问控制的一些实际应用。
- 验证
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个字符,也会被删减并添加。
- 提供对象的只读视图
有时候你可能要确保不以任何方式修改对象,并且只能将其用于读取目的。 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)
复制代码
现在,当你尝试以任何方式更改对象时,你只会收到一个字符串,表示只读。否则,你可能会引发错误以指示该对象是只读的。
- 私有属性
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
亚马逊测评www.yisuping.com