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:
parent
c7d9c5d138
commit
04f582da78
@ -317,6 +317,29 @@ const el = dom.div({},
|
|||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
如果一个属性不可配置(configurable)和不可写(writable),则该属性不能被代理,通过 Proxy 对象访问该属性会报错。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const target = Object.defineProperties({}, {
|
||||||
|
foo: {
|
||||||
|
value: 123,
|
||||||
|
writable: false,
|
||||||
|
configurable: false
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handler = {
|
||||||
|
get(target, propKey) {
|
||||||
|
return 'abc';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const proxy = new Proxy(target, handler);
|
||||||
|
|
||||||
|
proxy.foo
|
||||||
|
// TypeError: Invariant check failed
|
||||||
|
```
|
||||||
|
|
||||||
### set()
|
### set()
|
||||||
|
|
||||||
`set`方法用来拦截某个属性的赋值操作。
|
`set`方法用来拦截某个属性的赋值操作。
|
||||||
@ -380,6 +403,8 @@ proxy._prop = 'c'
|
|||||||
|
|
||||||
上面代码中,只要读写的属性名的第一个字符是下划线,一律抛错,从而达到禁止读写内部属性的目的。
|
上面代码中,只要读写的属性名的第一个字符是下划线,一律抛错,从而达到禁止读写内部属性的目的。
|
||||||
|
|
||||||
|
注意,如果目标对象自身的某个属性,不可写也不可配置,那么`set`不得改变这个属性的值,只能返回同样的值,否则报错。
|
||||||
|
|
||||||
### apply()
|
### apply()
|
||||||
|
|
||||||
`apply`方法拦截函数的调用、`call`和`apply`操作。
|
`apply`方法拦截函数的调用、`call`和`apply`操作。
|
||||||
@ -474,7 +499,7 @@ var p = new Proxy(obj, {
|
|||||||
'a' in p // TypeError is thrown
|
'a' in p // TypeError is thrown
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`obj`对象禁止扩展,结果使用`has`拦截就会报错。
|
上面代码中,`obj`对象禁止扩展,结果使用`has`拦截就会报错。也就是说,如果某个属性不可配置(或者目标对象不可扩展),则`has`方法就不得“隐藏”(即返回`false`)目标对象的该属性。
|
||||||
|
|
||||||
值得注意的是,`has`方法拦截的是`HasProperty`操作,而不是`HasOwnProperty`操作,即`has`方法不判断一个属性是对象自身的属性,还是继承的属性。
|
值得注意的是,`has`方法拦截的是`HasProperty`操作,而不是`HasOwnProperty`操作,即`has`方法不判断一个属性是对象自身的属性,还是继承的属性。
|
||||||
|
|
||||||
@ -588,6 +613,8 @@ delete proxy._prop
|
|||||||
|
|
||||||
上面代码中,`deleteProperty`方法拦截了`delete`操作符,删除第一个字符为下划线的属性会报错。
|
上面代码中,`deleteProperty`方法拦截了`delete`操作符,删除第一个字符为下划线的属性会报错。
|
||||||
|
|
||||||
|
注意,目标对象自身的不可配置(configurable)的属性,不能被`deleteProperty`方法删除,否则报错。
|
||||||
|
|
||||||
### defineProperty()
|
### defineProperty()
|
||||||
|
|
||||||
`defineProperty`方法拦截了`Object.defineProperty`操作。
|
`defineProperty`方法拦截了`Object.defineProperty`操作。
|
||||||
@ -606,6 +633,8 @@ proxy.foo = 'bar'
|
|||||||
|
|
||||||
上面代码中,`defineProperty`方法返回`false`,导致添加新属性会抛出错误。
|
上面代码中,`defineProperty`方法返回`false`,导致添加新属性会抛出错误。
|
||||||
|
|
||||||
|
注意,如果目标对象不可扩展(extensible),则`defineProperty`不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则`defineProperty`方法不得改变这两个设置。
|
||||||
|
|
||||||
### getOwnPropertyDescriptor()
|
### getOwnPropertyDescriptor()
|
||||||
|
|
||||||
`getOwnPropertyDescriptor`方法拦截`Object.getOwnPropertyDescriptor`,返回一个属性描述对象或者`undefined`。
|
`getOwnPropertyDescriptor`方法拦截`Object.getOwnPropertyDescriptor`,返回一个属性描述对象或者`undefined`。
|
||||||
@ -655,6 +684,8 @@ Object.getPrototypeOf(p) === proto // true
|
|||||||
|
|
||||||
上面代码中,`getPrototypeOf`方法拦截`Object.getPrototypeOf()`,返回`proto`对象。
|
上面代码中,`getPrototypeOf`方法拦截`Object.getPrototypeOf()`,返回`proto`对象。
|
||||||
|
|
||||||
|
注意,`getPrototypeOf`方法的返回值必须是对象或者`null`,否则报错。另外,如果目标对象不可扩展(extensible), `getPrototypeOf`方法必须返回目标对象的原型对象。
|
||||||
|
|
||||||
### isExtensible()
|
### isExtensible()
|
||||||
|
|
||||||
`isExtensible`方法拦截`Object.isExtensible`操作。
|
`isExtensible`方法拦截`Object.isExtensible`操作。
|
||||||
@ -674,7 +705,9 @@ Object.isExtensible(p)
|
|||||||
|
|
||||||
上面代码设置了`isExtensible`方法,在调用`Object.isExtensible`时会输出`called`。
|
上面代码设置了`isExtensible`方法,在调用`Object.isExtensible`时会输出`called`。
|
||||||
|
|
||||||
这个方法有一个强限制,如果不能满足下面的条件,就会抛出错误。
|
注意,该方法只能返回布尔值,否则返回值会被自动转为布尔值。
|
||||||
|
|
||||||
|
这个方法有一个强限制,它的返回值必须与目标对象的`isExtensible`属性保持一致,否则就会抛出错误。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
Object.isExtensible(proxy) === Object.isExtensible(target)
|
Object.isExtensible(proxy) === Object.isExtensible(target)
|
||||||
@ -855,9 +888,9 @@ Object.getOwnPropertyNames(p)
|
|||||||
|
|
||||||
### preventExtensions()
|
### preventExtensions()
|
||||||
|
|
||||||
`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值。
|
`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值,否则会被自动转为布尔值。
|
||||||
|
|
||||||
这个方法有一个限制,只有当`Object.isExtensible(proxy)`为`false`(即不可扩展)时,`proxy.preventExtensions`才能返回`true`,否则会报错。
|
这个方法有一个限制,只有目标对象不可扩展时(即`Object.isExtensible(proxy)`为`false`),`proxy.preventExtensions`才能返回`true`,否则会报错。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var p = new Proxy({}, {
|
var p = new Proxy({}, {
|
||||||
@ -876,7 +909,7 @@ Object.preventExtensions(p) // 报错
|
|||||||
```javascript
|
```javascript
|
||||||
var p = new Proxy({}, {
|
var p = new Proxy({}, {
|
||||||
preventExtensions: function(target) {
|
preventExtensions: function(target) {
|
||||||
console.log("called");
|
console.log('called');
|
||||||
Object.preventExtensions(target);
|
Object.preventExtensions(target);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -908,6 +941,8 @@ proxy.setPrototypeOf(proxy, proto);
|
|||||||
|
|
||||||
上面代码中,只要修改`target`的原型对象,就会报错。
|
上面代码中,只要修改`target`的原型对象,就会报错。
|
||||||
|
|
||||||
|
注意,该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展(extensible),`setPrototypeOf`方法不得改变目标对象的原型。
|
||||||
|
|
||||||
## Proxy.revocable()
|
## Proxy.revocable()
|
||||||
|
|
||||||
`Proxy.revocable`方法返回一个可取消的 Proxy 实例。
|
`Proxy.revocable`方法返回一个可取消的 Proxy 实例。
|
||||||
@ -927,6 +962,8 @@ proxy.foo // TypeError: Revoked
|
|||||||
|
|
||||||
`Proxy.revocable`方法返回一个对象,该对象的`proxy`属性是`Proxy`实例,`revoke`属性是一个函数,可以取消`Proxy`实例。上面代码中,当执行`revoke`函数之后,再访问`Proxy`实例,就会抛出一个错误。
|
`Proxy.revocable`方法返回一个对象,该对象的`proxy`属性是`Proxy`实例,`revoke`属性是一个函数,可以取消`Proxy`实例。上面代码中,当执行`revoke`函数之后,再访问`Proxy`实例,就会抛出一个错误。
|
||||||
|
|
||||||
|
`Proxy.revocable`的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
|
||||||
|
|
||||||
## this 问题
|
## this 问题
|
||||||
|
|
||||||
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的`this`关键字会指向 Proxy 代理。
|
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的`this`关键字会指向 Proxy 代理。
|
||||||
@ -998,3 +1035,32 @@ const proxy = new Proxy(target, handler);
|
|||||||
proxy.getDate() // 1
|
proxy.getDate() // 1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 应用实例
|
||||||
|
|
||||||
|
### Web 服务器的客户端
|
||||||
|
|
||||||
|
Proxy 对象可以拦截目标对象的任意属性,这使得它很合适用来写 Web 服务的客户端。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const service = createWebService('http://example.com/data');
|
||||||
|
|
||||||
|
service.employees().then(json => {
|
||||||
|
const employees = JSON.parse(json);
|
||||||
|
// ···
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码新建了一个 Web 服务的接口,这个接口返回各种数据。Proxy 可以拦截这个对象的任意属性,所以不用为每一种数据写一个适配方法,只要写一个 Proxy 拦截就可以了。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function createWebService(baseUrl) {
|
||||||
|
return new Proxy({}, {
|
||||||
|
get(target, propKey, receiver) {
|
||||||
|
return () => httpGet(baseUrl+'/' + propKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同理,Proxy 也可以用来实现数据库的 ORM 层。
|
||||||
|
|
||||||
|
@ -225,6 +225,8 @@ delete myObj.foo;
|
|||||||
Reflect.deleteProperty(myObj, 'foo');
|
Reflect.deleteProperty(myObj, 'foo');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
该方法返回一个布尔值。如果删除成功,或者被删除的属性不存在,返回`true`;删除失败,被删除的属性依然存在,返回`false`。
|
||||||
|
|
||||||
### Reflect.construct(target, args)
|
### Reflect.construct(target, args)
|
||||||
|
|
||||||
`Reflect.construct`方法等同于`new target(...args)`,这提供了一种不使用`new`,来调用构造函数的方法。
|
`Reflect.construct`方法等同于`new target(...args)`,这提供了一种不使用`new`,来调用构造函数的方法。
|
||||||
|
@ -139,7 +139,7 @@ function init_back_to_top_button() {
|
|||||||
|
|
||||||
function goTop(e) {
|
function goTop(e) {
|
||||||
if(e) e.preventDefault();
|
if(e) e.preventDefault();
|
||||||
$('html body').animate({
|
$('html, body').animate({
|
||||||
scrollTop: 0
|
scrollTop: 0
|
||||||
}, 200);
|
}, 200);
|
||||||
history.pushState(null, null, '#' + location.hash.split('#')[1]);
|
history.pushState(null, null, '#' + location.hash.split('#')[1]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user