Javascript Proxy对象javascript
改变你操做对象的方式java
Proxies 是Javasript对象的中间件函数
...或者说至少是那种很早的版本。this
ES6 中引入Proxies,让你能够自定义Object
的基本操做。例如,get
就是Object
的基础操做方法。spa
const obj = { val: 10 };
console.log(obj.val);
这里,console.log()
表达式在对象obj
上执行get
方法来获取val
的值。操作系统
另外一个对象的基本操做方法是 set
。3d
const obj = { val: 10 };
obj.val2 = 20;
这里,set
方法用来给对象obj
设置一个新的值。code
const proxiedObject = new Proxy(initialObj, handler);
调用Proxy构造函数,new Proxy()
将返回一个对象,不只包含了initialObj
里的值,并且其基本操做(如get
和 set
)如今能够经过handler
对象来指定一些自定义逻辑。中间件
咱们写个例子来理解这个概念,对象
const handler = { get: function() { console.log('A value has been accessed'); } } const initialObj = { id: 1, name: 'Foo Bar' } const proxiedObj = new Proxy(initialObj, handler); console.log(proxiedObj.name);
如今,若是咱们没有构造一个Proxy对象,执行第14行的console.log(proxiedObj.name)
会在控制台输出 “Foo Bar”。
不过如今咱们定义了一个Proxy,并在第三行get
方法中定义了一些自定义逻辑。
如今执行console.log(proxiedObj.name)
会在控制台输出 “A value has been accessed”。
仔细看,你会发现控制台中实际上有两条记录。 “A value has been accessed” 和 undefined
。 为何?
get
运算符的默认实现是返回Object中存储的值。因为咱们将它重写为只记录一条语句,该值永远不会返回,所以第14行的console.log()
输出undefined
。
让咱们来解决这个问题!
get
运算符有两个参数 - 对象自己和被访问的属性。
const handler = { get: function(obj, prop) { console.log('A value has been accessed'); return obj[prop]; // 返回访问的key在obj的值 } } const initialObj = { id: 1, name: 'Foo Bar' } const proxiedObj = new Proxy(initialObj, handler); console.log(proxiedObj.name);
返回属性值
返回属性值 --- 控制台的输出
好多了吧!
咱们为get
提供的自定义覆盖被称为“拦截器”(大概基于操做系统拦截的概念)。 handler
对象基本上是一个包含一组“拦截”的对象,每当访问对象属性时都会被触发。
咱们给set
也添加一个“拦截器”。 咱们将作一样的事情 - 任什么时候候设置一个值,咱们将记录被修改的属性,以及为该键设置的值。
set
操做符有三个参数 - 对象自己,被访问的属性和为该属性设置的值。
const handler = { get: function(obj, prop) { console.log('A value has been accessed'); return obj[prop]; }, set: function(obj, prop, value) { console.log(`${prop} is being set to ${value}`); } } const initialObj = { id: 1, name: 'Foo Bar' } const proxiedObj = new Proxy(initialObj, handler); proxiedObj.age = 24
添加`set` “拦截器”
这里,在第18行进行的访问将触发第6行定义的功能,该功能将记录正在访问的属性和正在设置的值。
`Set` “拦截器” —— 控制台的输出
假设咱们有一个定义叫person的对象
const person = { id: 1, name: 'Foo Bar' };
若是咱们想让这个对象的id属性是一个私有属性呢? 没人可以经过person.id访问这个属性,若是有人这样作,咱们须要抛出一个错误。 咱们将如何作到这一点?
让Proxies来拯救吧!
咱们所须要作的就是给这个对象建立一个Proxy,并覆盖get
运算符来阻止咱们访问id
属性!
const handler = { get: function(obj, prop) { if (prop === 'id') { // Check if the id is being accessed throw new Error('Cannot access private properties!'); // Throw an error } else { return obj[prop]; // If it's not the id property, return it as usual } } } const person = { id: 1, name: 'Foo Bar' } const proxiedPerson = new Proxy(person, handler); console.log(proxiedPerson.id);
阻止访问私有属性
这里,在咱们给get
建立的“拦截器”,咱们检查被访问的属性是不是id
属性,若是是的话,咱们会抛出一个错误。 不然,咱们照常返回值。
私有属性 — 控制台输出
另外一个极好的用例是校验。 经过设置set
“拦截器”,咱们能够在设置值以前添加自定义验证。 若是该值不符合验证,咱们能够抛出一个错误!
const handler = { set: function(obj, prop, value) { if (typeof value !== 'string') { throw new Error('Only string values can be stored in this object!'); } else { obj[prop] = value; } } } const obj = {}; const proxiedObj = new Proxy(obj, handler); console.log(proxiedObj); // This will log an empty object proxiedObj.name = 'Foo Bar'; // This should be allowed console.log(proxiedObj); // This will log an object with the name property set proxiedObj.age = 24; // This will throw an error.
自定义对象的属性校验
自定义校验 - 控制台输出
在上面的例子中,咱们已经看到了get
和set
“陷阱”。 实际上能够设置更多的“陷阱”。 你能够在这里找到整个列表。
Proxy对象只是在阅读关于它们的这篇文章以后才进入个人视野,我已经能够在我天天写的代码中看到它们的用处了!