1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 10:22:23 +00:00

docs(proxy): edit proxy

This commit is contained in:
ruanyf 2016-11-27 23:28:35 +08:00
parent 95f8979eb7
commit ba0744a7a4
2 changed files with 89 additions and 17 deletions

View File

@ -38,7 +38,7 @@ ES6原生提供Proxy构造函数用来生成Proxy实例。
var proxy = new Proxy(target, handler);
```
Proxy对象的所有用法都是上面这种形式不同的只是`handler`参数的写法。其中,`new Proxy()`表示生成一个Proxy实例target参数表示所要拦截的目标对象`handler`参数也是一个对象,用来定制拦截行为。
Proxy 对象的所有用法,都是上面这种形式,不同的只是`handler`参数的写法。其中,`new Proxy()`表示生成一个`Proxy`实例,`target`参数表示所要拦截的目标对象,`handler`参数也是一个对象,用来定制拦截行为。
下面是另一个拦截读取属性行为的例子。
@ -54,9 +54,9 @@ proxy.name // 35
proxy.title // 35
```
上面代码中作为构造函数Proxy接受两个参数。第一个参数是所要代理的目标对象上例是一个空对象即如果没有Proxy的介入操作原来要访问的就是这个对象第二个参数是一个配置对象对于每一个被代理的操作需要提供一个对应的处理函数该函数将拦截对应的操作。比如上面代码中配置对象有一个`get`方法,用来拦截对目标对象属性的访问请求。`get`方法的两个参数分别是目标对象和所要访问的属性。可以看到,由于拦截函数总是返回`35`,所以访问任何属性都得到`35`
上面代码中,作为构造函数,`Proxy`接受两个参数。第一个参数是所要代理的目标对象(上例是一个空对象),即如果没有`Proxy`的介入,操作原来要访问的就是这个对象;第二个参数是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。比如,上面代码中,配置对象有一个`get`方法,用来拦截对目标对象属性的访问请求。`get`方法的两个参数分别是目标对象和所要访问的属性。可以看到,由于拦截函数总是返回`35`,所以访问任何属性都得到`35`
注意要使得Proxy起作用必须针对Proxy实例上例是proxy对象进行操作而不是针对目标对象上例是空对象进行操作。
注意,要使得`Proxy`起作用,必须针对`Proxy`实例(上例是`proxy`对象)进行操作,而不是针对目标对象(上例是空对象)进行操作。
如果`handler`没有设置任何拦截,那就等同于直接通向原对象。
@ -224,7 +224,7 @@ let obj = Object.create(proto);
obj.xxx // "GET xxx"
```
上面代码中拦截操作定义在Prototype对象上面所以如果读取`obj`对象继承的属性时,拦截会生效。
上面代码中,拦截操作定义在`Prototype`对象上面,所以如果读取`obj`对象继承的属性时,拦截会生效。
下面的例子使用`get`拦截,实现数组读取负数的索引。
@ -808,6 +808,77 @@ proxy.foo // TypeError: Revoked
`Proxy.revocable`方法返回一个对象,该对象的`proxy`属性是`Proxy`实例,`revoke`属性是一个函数,可以取消`Proxy`实例。上面代码中,当执行`revoke`函数之后,再访问`Proxy`实例,就会抛出一个错误。
## this 问题
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的`this`关键字会指向 Proxy 代理。
```javascript
const target = {
m: function () {
console.log(this === proxy);
}
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m() // true
```
上面代码中,一旦`proxy`代理`target.m`,后者内部的`this`就是指向`proxy`,而不是`target`
下面是一个例子,由于`this`指向的变化,导致 Proxy 无法代理目标对象。
```javascript
const _name = new WeakMap();
class Person {
constructor(name) {
_name.set(this, name);
}
get name() {
return _name.get(this);
}
}
const jane = new Person('Jane');
jane.name // 'Jane'
const proxy = new Proxy(jane, {});
proxy.name // undefined
```
上面代码中,目标对象`jane``name`属性,实际保存在外部`WeakMap`对象`_name`上面,通过`this`键区分。由于通过`proxy.name`访问时,`this`指向`proxy`,导致无法取到值,所以返回`undefined`
此外,有些原生对象的内部属性,只有通过正确的`this`才能拿到,所以 Proxy 也无法代理这些原生对象的属性。
```javascript
const target = new Date();
const handler = {};
const proxy = new Proxy(target, handler);
proxy.getDate();
// TypeError: this is not a Date object.
```
上面代码中,`getDate`方法只能在`Date`对象实例上面拿到,如果`this`不是`Date`对象实例就会报错。这时,`this`绑定原始对象,就可以解决这个问题。
```javascript
const target = new Date('2015-01-01');
const handler = {
get(target, prop) {
if (prop === 'getDate') {
return target.getDate.bind(target);
}
return Reflect.get(target, prop);
}
};
const proxy = new Proxy(target, handler);
proxy.getDate() // 1
```
## Reflect概述
`Reflect`对象与`Proxy`对象一样也是ES6为了操作对象而提供的新API。`Reflect`对象的设计目的有这样几个。
@ -914,7 +985,7 @@ Reflect.apply(Math.floor, undefined, [1.75]) // 1
查找并返回`target`对象的`name`属性,如果没有该属性,则返回`undefined`
如果`name`属性部署了读取函数则读取函数的this绑定`receiver`
如果`name`属性部署了读取函数,则读取函数的`this`绑定`receiver`
```javascript
var obj = {

View File

@ -106,6 +106,7 @@
- Nicolas Bevacqua, [ES6 Proxies in Depth](http://ponyfoo.com/articles/es6-proxies-in-depth)
- Nicolas Bevacqua, [ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/es6-proxy-traps-in-depth)
- Nicolas Bevacqua, [More ES6 Proxy Traps in Depth](http://ponyfoo.com/articles/more-es6-proxy-traps-in-depth)
- Axel Rauschmayer, [Pitfall: not all objects can be wrapped transparently by proxies](http://www.2ality.com/2016/11/proxying-builtins.html)
## Symbol